Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (279888 => 279889)
--- trunk/Source/_javascript_Core/ChangeLog 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-07-13 20:38:20 UTC (rev 279889)
@@ -1,3 +1,60 @@
+2021-07-13 Yijia Huang <[email protected]>
+
+ Add a new Air::Arg kind ZeroReg to let AIR recognise the new instructions/forms accepting zero register in ARM64
+ https://bugs.webkit.org/show_bug.cgi?id=227510
+
+ Reviewed by Saam Barati.
+
+ B3 is designed to be portable to many kinds of CPUs. However, to effectively
+ compile code to different CPUs, the compiler must eventually make explicit
+ instruction set details. Then, Air is introduced, and it is designed to target
+ individual CPU architectures and generate instructions specific to those CPUs.
+
+ Previously, Air don't recognize the zero register. This problem has been pointed
+ out in #174821, which was trying to introduce the new opcodes to handle the zero
+ register.
+
+ To solve this problem in a modular reasoning approach, a new Air operand ZeroReg
+ should be introduced. Its goal is to closely match the CPU instructions
+ accepting the zero register in ARM64. Another reason is that the new overloads
+ of the instructions taking the zero register can benefit instruction selection
+ with this implementation.
+
+ Here, the ZeroReg is added as a new kind for Air::Arg, which acts as a "high
+ level" operand to be emitted with the associative opcodes. In ARM64, the ZeroReg
+ would be emitted as a zero register.
+
+ * assembler/MacroAssemblerARM64.h:
+ (JSC::MacroAssemblerARM64::storeZero64): Deleted.
+ (JSC::MacroAssemblerARM64::storeZero32): Deleted.
+ (JSC::MacroAssemblerARM64::storeZero16): Deleted.
+ * assembler/MacroAssemblerX86Common.h:
+ (JSC::MacroAssemblerX86Common::storeZero32): Deleted.
+ (JSC::MacroAssemblerX86Common::storeZero16): Deleted.
+ * assembler/MacroAssemblerX86_64.h:
+ (JSC::MacroAssemblerX86_64::storeZero64): Deleted.
+ * b3/B3LowerToAir.cpp:
+ * b3/air/AirArg.cpp:
+ (JSC::B3::Air::Arg::jsHash const):
+ (JSC::B3::Air::Arg::dump const):
+ (WTF::printInternal):
+ * b3/air/AirArg.h:
+ (JSC::B3::Air::Arg::zeroReg):
+ (JSC::B3::Air::Arg::isZeroReg const):
+ (JSC::B3::Air::Arg::isGP const):
+ (JSC::B3::Air::Arg::isFP const):
+ (JSC::B3::Air::Arg::isValidForm const):
+ (JSC::B3::Air::Arg::asZeroReg const):
+ * b3/air/AirLowerStackArgs.cpp:
+ (JSC::B3::Air::lowerStackArgs):
+ * b3/air/AirOpcode.opcodes:
+ * b3/air/opcode_generator.rb:
+ * b3/testb3.h:
+ * b3/testb3_1.cpp:
+ (run):
+ * b3/testb3_3.cpp:
+ (testStoreZeroReg):
+
2021-07-12 Filip Pizlo <[email protected]> and Yusuke Suzuki <[email protected]>
New malloc algorithm
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (279888 => 279889)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2021-07-13 20:38:20 UTC (rev 279889)
@@ -1731,16 +1731,6 @@
m_assembler.str<64>(src, dest, simm);
}
- void storeZero64(ImplicitAddress address)
- {
- store64(ARM64Registers::zr, address);
- }
-
- void storeZero64(BaseIndex address)
- {
- store64(ARM64Registers::zr, address);
- }
-
DataLabel32 store64WithAddressOffsetPatch(RegisterID src, Address address)
{
DataLabel32 label(this);
@@ -1838,16 +1828,6 @@
store32(dataTempRegister, address);
}
- void storeZero32(ImplicitAddress address)
- {
- store32(ARM64Registers::zr, address);
- }
-
- void storeZero32(BaseIndex address)
- {
- store32(ARM64Registers::zr, address);
- }
-
DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
{
DataLabel32 label(this);
@@ -1893,16 +1873,6 @@
store16(dataTempRegister, address);
}
- void storeZero16(ImplicitAddress address)
- {
- store16(ARM64Registers::zr, address);
- }
-
- void storeZero16(BaseIndex address)
- {
- store16(ARM64Registers::zr, address);
- }
-
void store8(RegisterID src, BaseIndex address)
{
if (!address.offset && !address.scale) {
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (279888 => 279889)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2021-07-13 20:38:20 UTC (rev 279889)
@@ -1337,26 +1337,6 @@
m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale);
}
- void storeZero32(ImplicitAddress address)
- {
- store32(TrustedImm32(0), address);
- }
-
- void storeZero32(BaseIndex address)
- {
- store32(TrustedImm32(0), address);
- }
-
- void storeZero16(ImplicitAddress address)
- {
- store16(TrustedImm32(0), address);
- }
-
- void storeZero16(BaseIndex address)
- {
- store16(TrustedImm32(0), address);
- }
-
void store8(TrustedImm32 imm, Address address)
{
TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h (279888 => 279889)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h 2021-07-13 20:38:20 UTC (rev 279889)
@@ -1015,16 +1015,6 @@
m_assembler.movq_rm(scratchRegister(), address.offset, address.base, address.index, address.scale);
}
- void storeZero64(ImplicitAddress address)
- {
- store64(TrustedImm32(0), address);
- }
-
- void storeZero64(BaseIndex address)
- {
- store64(TrustedImm32(0), address);
- }
-
DataLabel32 store64WithAddressOffsetPatch(RegisterID src, Address address)
{
padBeforePatch();
Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (279888 => 279889)
--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2021-07-13 20:38:20 UTC (rev 279889)
@@ -702,6 +702,11 @@
return Arg();
}
+ Arg zeroReg()
+ {
+ return Arg::zeroReg();
+ }
+
Arg immOrTmp(Value* value)
{
if (Arg result = imm(value))
@@ -1094,17 +1099,17 @@
{
using namespace Air;
if (auto imm_value = imm(value)) {
- if (isARM64() && imm_value.value() == 0) {
+ if (!imm_value.value()) {
switch (move.opcode) {
default:
break;
case Air::Move32:
- if (isValidForm(StoreZero32, dest.kind()) && dest.isValidForm(Width32))
- return Inst(StoreZero32, m_value, dest);
+ if (isValidForm(Store32, Arg::ZeroReg, dest.kind()) && dest.isValidForm(Width32))
+ return Inst(Store32, m_value, zeroReg(), dest);
break;
case Air::Move:
- if (isValidForm(StoreZero64, dest.kind()) && dest.isValidForm(Width64))
- return Inst(StoreZero64, m_value, dest);
+ if (isValidForm(Store64, Arg::ZeroReg, dest.kind()) && dest.isValidForm(Width64))
+ return Inst(Store64, m_value, zeroReg(), dest);
break;
}
}
Modified: trunk/Source/_javascript_Core/b3/air/AirArg.cpp (279888 => 279889)
--- trunk/Source/_javascript_Core/b3/air/AirArg.cpp 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.cpp 2021-07-13 20:38:20 UTC (rev 279889)
@@ -102,6 +102,7 @@
break;
case Imm:
case BitImm:
+ case ZeroReg:
case CallArg:
case RelCond:
case ResCond:
@@ -159,6 +160,9 @@
case BitImm64:
out.printf("$0x%llx", static_cast<long long unsigned>(m_offset));
return;
+ case ZeroReg:
+ out.print("%%xzr");
+ return;
case SimpleAddr:
out.print("(", base(), ")");
return;
@@ -236,6 +240,9 @@
case Arg::BitImm64:
out.print("BitImm64");
return;
+ case Arg::ZeroReg:
+ out.print("ZeroReg");
+ return;
case Arg::SimpleAddr:
out.print("SimpleAddr");
return;
Modified: trunk/Source/_javascript_Core/b3/air/AirArg.h (279888 => 279889)
--- trunk/Source/_javascript_Core/b3/air/AirArg.h 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.h 2021-07-13 20:38:20 UTC (rev 279889)
@@ -85,7 +85,10 @@
DoubleCond,
StatusCond,
Special,
- WidthArg
+ WidthArg,
+
+ // ZeroReg is interpreted as a zero register in ARM64
+ ZeroReg
};
enum Temperature : int8_t {
@@ -693,6 +696,14 @@
return result;
}
+ static Arg zeroReg()
+ {
+ Arg result;
+ result.m_kind = ZeroReg;
+ result.m_offset = 0;
+ return result;
+ }
+
bool operator==(const Arg& other) const
{
return m_offset == other.m_offset
@@ -739,6 +750,11 @@
return kind() == BitImm64;
}
+ bool isZeroReg() const
+ {
+ return kind() == ZeroReg;
+ }
+
bool isSomeImm() const
{
switch (kind()) {
@@ -1022,6 +1038,7 @@
case BigImm:
case BitImm:
case BitImm64:
+ case ZeroReg:
case SimpleAddr:
case Addr:
case ExtendedOffsetAddr:
@@ -1057,6 +1074,7 @@
case Special:
case WidthArg:
case Invalid:
+ case ZeroReg:
return false;
case SimpleAddr:
case Addr:
@@ -1236,6 +1254,7 @@
return isValidBitImmForm(value());
case BitImm64:
return isValidBitImm64Form(value());
+ case ZeroReg:
case SimpleAddr:
case ExtendedOffsetAddr:
return true;
@@ -1331,6 +1350,13 @@
}
#endif
+#if CPU(ARM64)
+ MacroAssembler::RegisterID asZeroReg() const
+ {
+ return ARM64Registers::zr;
+ }
+#endif
+
MacroAssembler::TrustedImmPtr asTrustedImmPtr() const
{
if (is64Bit())
Modified: trunk/Source/_javascript_Core/b3/air/AirLowerStackArgs.cpp (279888 => 279889)
--- trunk/Source/_javascript_Core/b3/air/AirLowerStackArgs.cpp 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/b3/air/AirLowerStackArgs.cpp 2021-07-13 20:38:20 UTC (rev 279889)
@@ -157,9 +157,20 @@
RELEASE_ASSERT(slot->byteSize() == 8);
RELEASE_ASSERT(width == Width32);
- RELEASE_ASSERT(isValidForm(StoreZero32, Arg::Stack));
+#if CPU(ARM64)
+ Air::Opcode storeOpcode = Store32;
+ Air::Arg::Kind operandKind = Arg::ZeroReg;
+ Air::Arg operand = Arg::zeroReg();
+#elif CPU(X86_64)
+ Air::Opcode storeOpcode = Move32;
+ Air::Arg::Kind operandKind = Arg::Imm;
+ Air::Arg operand = Arg::imm(0);
+#else
+#error Unhandled architecture.
+#endif
+ RELEASE_ASSERT(isValidForm(storeOpcode, operandKind, Arg::Stack));
insertionSet.insert(
- instIndex + 1, StoreZero32, inst.origin,
+ instIndex + 1, storeOpcode, inst.origin, operand,
stackAddr(arg.offset() + 4 + slot->offsetFromFP()));
}
arg = stackAddr(arg.offset() + slot->offsetFromFP());
Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (279888 => 279889)
--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2021-07-13 20:38:20 UTC (rev 279889)
@@ -675,14 +675,13 @@
Move32 U:G:32, ZD:G:32, S:G:32
Addr, Addr, Tmp
-# FIXME: StoreZero32 and StoreZero64 are hacks on ARM64, we can do better: https://bugs.webkit.org/show_bug.cgi?id=174821
-StoreZero32 D:G:32
- Addr
- Index
+arm64: Store32 U:G:32, ZD:G:32
+ ZeroReg, Addr
+ ZeroReg, Index
-64: StoreZero64 D:G:64
- Addr
- Index
+arm64: Store64 U:G:64, D:G:64
+ ZeroReg, Addr
+ ZeroReg, Index
SignExtend32ToPtr U:G:32, D:G:Ptr
Tmp, Tmp
Modified: trunk/Source/_javascript_Core/b3/air/opcode_generator.rb (279888 => 279889)
--- trunk/Source/_javascript_Core/b3/air/opcode_generator.rb 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/b3/air/opcode_generator.rb 2021-07-13 20:38:20 UTC (rev 279889)
@@ -229,7 +229,7 @@
end
def isKind(token)
- token =~ /\A((Tmp)|(Imm)|(BigImm)|(BitImm)|(BitImm64)|(SimpleAddr)|(Addr)|(ExtendedOffsetAddr)|(Index)|(RelCond)|(ResCond)|(DoubleCond)|(StatusCond))\Z/
+ token =~ /\A((Tmp)|(Imm)|(BigImm)|(BitImm)|(BitImm64)|(ZeroReg)|(SimpleAddr)|(Addr)|(ExtendedOffsetAddr)|(Index)|(RelCond)|(ResCond)|(DoubleCond)|(StatusCond))\Z/
end
def isArch(token)
@@ -303,7 +303,7 @@
def consumeKind
result = token.string
- parseError("Expected kind (Imm, BigImm, BitImm, BitImm64, Tmp, SimpleAddr, Addr, ExtendedOffsetAddr, Index, RelCond, ResCond, DoubleCond, or StatusCond)") unless isKind(result)
+ parseError("Expected kind (Imm, BigImm, BitImm, BitImm64, ZeroReg, Tmp, SimpleAddr, Addr, ExtendedOffsetAddr, Index, RelCond, ResCond, DoubleCond, or StatusCond)") unless isKind(result)
advance
result
end
@@ -475,6 +475,14 @@
parseError("Form has an immediate for a non-general-purpose argument")
end
end
+ if kind.name == "ZeroReg"
+ if signature[index].role != "U"
+ parseError("Zero immediate must be a use argument")
+ end
+ if signature[index].bank != "G"
+ parseError("Zero immediate must be a general-purpose argument")
+ end
+ end
}
forms << Form.new(kinds, altName, intersectArchs(opcodeArchs, formArchs))
@@ -926,6 +934,7 @@
when "ResCond"
when "DoubleCond"
when "StatusCond"
+ when "ZeroReg"
else
raise "Unexpected kind: #{kind.name}"
end
@@ -1220,6 +1229,8 @@
outp.print "args[#{index}].asTrustedImm32()"
when "BigImm", "BitImm64"
outp.print "args[#{index}].asTrustedImm64()"
+ when "ZeroReg"
+ outp.print "args[#{index}].asZeroReg()"
when "SimpleAddr", "Addr", "ExtendedOffsetAddr"
outp.print "args[#{index}].asAddress()"
when "Index"
Modified: trunk/Source/_javascript_Core/b3/testb3.h (279888 => 279889)
--- trunk/Source/_javascript_Core/b3/testb3.h 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/b3/testb3.h 2021-07-13 20:38:20 UTC (rev 279889)
@@ -681,6 +681,7 @@
void testIToF32Imm(int32_t value);
void testIToDReducedToIToF64Arg();
void testIToDReducedToIToF32Arg();
+void testStoreZeroReg();
void testStore32(int value);
void testStoreConstant(int value);
void testStoreConstantPtr(intptr_t value);
Modified: trunk/Source/_javascript_Core/b3/testb3_1.cpp (279888 => 279889)
--- trunk/Source/_javascript_Core/b3/testb3_1.cpp 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/b3/testb3_1.cpp 2021-07-13 20:38:20 UTC (rev 279889)
@@ -338,6 +338,7 @@
RUN_UNARY(testCheckAddRemoveCheckWithSExt32, int32Operands());
RUN_UNARY(testCheckAddRemoveCheckWithZExt32, int32Operands());
+ RUN(testStoreZeroReg());
RUN(testStore32(44));
RUN(testStoreConstant(49));
RUN(testStoreConstantPtr(49));
Modified: trunk/Source/_javascript_Core/b3/testb3_3.cpp (279888 => 279889)
--- trunk/Source/_javascript_Core/b3/testb3_3.cpp 2021-07-13 20:13:07 UTC (rev 279888)
+++ trunk/Source/_javascript_Core/b3/testb3_3.cpp 2021-07-13 20:38:20 UTC (rev 279889)
@@ -2888,6 +2888,83 @@
CHECK(isIdentical(invoke<float>(*code, testValue.value), static_cast<float>(testValue.value)));
}
+void testStoreZeroReg()
+{
+ // Direct addressing
+ {
+ int32_t slot32 = 0xbaadbeef;
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* value = root->appendNew<Const32Value>(proc, Origin(), 0);
+ root->appendNew<MemoryValue>(
+ proc, Store, Origin(), value,
+ root->appendNew<ConstPtrValue>(proc, Origin(), &slot32), 0);
+ root->appendNewControlValue(proc, Return, Origin(), value);
+
+ auto code = compileProc(proc);
+ invoke<int>(*code);
+ CHECK_EQ(slot32, 0);
+ }
+
+ {
+ int64_t slot64 = 0xbaadbeef;
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* value = root->appendNew<Const64Value>(proc, Origin(), 0);
+ root->appendNew<MemoryValue>(
+ proc, Store, Origin(), value,
+ root->appendNew<ConstPtrValue>(proc, Origin(), &slot64), 0);
+ root->appendNewControlValue(proc, Return, Origin(), value);
+
+ auto code = compileProc(proc);
+ invoke<int>(*code);
+ CHECK_EQ(slot64, 0);
+ }
+
+ // Indexed addressing
+ {
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* value = root->appendNew<Const32Value>(proc, Origin(), 0);
+ Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+ Value* displacement = root->appendNew<Const64Value>(proc, Origin(), -1);
+
+ Value* baseDisplacement = root->appendNew<Value>(proc, Add, Origin(), displacement, base);
+ Value* address = root->appendNew<Value>(proc, Add, Origin(), baseDisplacement, offset);
+
+ root->appendNew<MemoryValue>(proc, Store, Origin(), value, address, 0);
+ root->appendNewControlValue(proc, Return, Origin(), value);
+
+ int32_t slot32 = 0xbaadbeef;
+ compileAndRun<int32_t>(proc, &slot32, 1);
+ CHECK_EQ(slot32, 0);
+ }
+
+ {
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* value = root->appendNew<Const64Value>(proc, Origin(), 0);
+ Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+ Value* displacement = root->appendNew<Const64Value>(proc, Origin(), -1);
+
+ Value* baseDisplacement = root->appendNew<Value>(proc, Add, Origin(), displacement, base);
+ Value* address = root->appendNew<Value>(proc, Add, Origin(), baseDisplacement, offset);
+
+ root->appendNew<MemoryValue>(proc, Store, Origin(), value, address, 0);
+ root->appendNewControlValue(proc, Return, Origin(), value);
+
+ int64_t slot64 = 0xbaadbeef;
+ compileAndRun<int64_t>(proc, &slot64, 1);
+ CHECK_EQ(slot64, 0);
+ }
+}
+
void testStore32(int value)
{
Procedure proc;