Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (192698 => 192699)
--- trunk/Source/_javascript_Core/ChangeLog 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-11-20 22:31:19 UTC (rev 192699)
@@ -1,3 +1,98 @@
+2015-11-20 Filip Pizlo <fpi...@apple.com>
+
+ B3 should have a Select opcode
+ https://bugs.webkit.org/show_bug.cgi?id=150762
+
+ Reviewed by Benjamin Poulain.
+
+ This cleans up our conditional move implementation - specifically so that it distinguishes between
+ comparing the low 32 bits of a GPR and all bits of a GPR - and fixes bugs with operand ordering. It
+ then adds a Select opcode to B3 and adds all of the strength reduction and lowering magic that it
+ needs. Finally this change implements FTL::Output::select() in terms of B3::Select.
+
+ This patch lets us run Kraken/imaging-gaussian-blur. Running that benchmark using FTL+B3 is a 17%
+ speed-up. The compile times go down dramatically (by about 7x) and code quality stays about the same.
+
+ * assembler/MacroAssembler.h:
+ (JSC::MacroAssembler::moveDoubleConditionally32):
+ (JSC::MacroAssembler::moveDoubleConditionally64):
+ (JSC::MacroAssembler::moveDoubleConditionallyTest32):
+ (JSC::MacroAssembler::moveDoubleConditionallyTest64):
+ (JSC::MacroAssembler::moveDoubleConditionallyDouble):
+ (JSC::MacroAssembler::lea):
+ * assembler/MacroAssemblerX86Common.h:
+ (JSC::MacroAssemblerX86Common::move):
+ (JSC::MacroAssemblerX86Common::moveConditionallyDouble):
+ (JSC::MacroAssemblerX86Common::zeroExtend32ToPtr):
+ (JSC::MacroAssemblerX86Common::moveConditionally32):
+ (JSC::MacroAssemblerX86Common::moveConditionallyTest32):
+ (JSC::MacroAssemblerX86Common::set32):
+ (JSC::MacroAssemblerX86Common::cmov):
+ (JSC::MacroAssemblerX86Common::moveConditionally): Deleted.
+ (JSC::MacroAssemblerX86Common::moveConditionallyTest): Deleted.
+ * assembler/MacroAssemblerX86_64.h:
+ (JSC::MacroAssemblerX86_64::branchNeg64):
+ (JSC::MacroAssemblerX86_64::moveConditionally64):
+ (JSC::MacroAssemblerX86_64::moveConditionallyTest64):
+ (JSC::MacroAssemblerX86_64::abortWithReason):
+ * assembler/X86Assembler.h:
+ (JSC::X86Assembler::cmovl_rr):
+ (JSC::X86Assembler::cmovl_mr):
+ (JSC::X86Assembler::cmovel_rr):
+ (JSC::X86Assembler::cmovnel_rr):
+ (JSC::X86Assembler::cmovpl_rr):
+ (JSC::X86Assembler::cmovnpl_rr):
+ (JSC::X86Assembler::cmovq_rr):
+ (JSC::X86Assembler::cmovq_mr):
+ (JSC::X86Assembler::cmoveq_rr):
+ (JSC::X86Assembler::cmovneq_rr):
+ (JSC::X86Assembler::cmovpq_rr):
+ (JSC::X86Assembler::cmovnpq_rr):
+ * b3/B3LowerToAir.cpp:
+ (JSC::B3::Air::LowerToAir::createCompare):
+ (JSC::B3::Air::LowerToAir::createSelect):
+ (JSC::B3::Air::LowerToAir::marshallCCallArgument):
+ (JSC::B3::Air::LowerToAir::lower):
+ * b3/B3MoveConstants.cpp:
+ * b3/B3Opcode.cpp:
+ (WTF::printInternal):
+ * b3/B3Opcode.h:
+ * b3/B3ReduceStrength.cpp:
+ * b3/B3Validate.cpp:
+ * b3/B3Value.cpp:
+ (JSC::B3::Value::effects):
+ (JSC::B3::Value::key):
+ (JSC::B3::Value::checkOpcode):
+ (JSC::B3::Value::typeFor):
+ * b3/B3Value.h:
+ * b3/B3ValueKey.cpp:
+ (JSC::B3::ValueKey::dump):
+ (JSC::B3::ValueKey::materialize):
+ * b3/B3ValueKey.h:
+ (JSC::B3::ValueKey::ValueKey):
+ (JSC::B3::ValueKey::hash):
+ (JSC::B3::ValueKey::operator bool):
+ * b3/B3ValueKeyInlines.h:
+ (JSC::B3::ValueKey::ValueKey):
+ (JSC::B3::ValueKey::child):
+ * b3/air/AirOpcode.opcodes:
+ * b3/testb3.cpp:
+ (JSC::B3::testTruncSExt32):
+ (JSC::B3::testBasicSelect):
+ (JSC::B3::testSelectTest):
+ (JSC::B3::testSelectCompareDouble):
+ (JSC::B3::testSelectDouble):
+ (JSC::B3::testSelectDoubleTest):
+ (JSC::B3::testSelectDoubleCompareDouble):
+ (JSC::B3::zero):
+ (JSC::B3::run):
+ * ftl/FTLB3Output.h:
+ (JSC::FTL::Output::testIsZeroPtr):
+ (JSC::FTL::Output::testNonZeroPtr):
+ (JSC::FTL::Output::select):
+ (JSC::FTL::Output::extractValue):
+ (JSC::FTL::Output::fence):
+
2015-11-20 Benjamin Poulain <bpoul...@apple.com>
[JSC] Add Air lowering to BitNot() for Xor(value, -1)
Modified: trunk/Source/_javascript_Core/assembler/MacroAssembler.h (192698 => 192699)
--- trunk/Source/_javascript_Core/assembler/MacroAssembler.h 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/assembler/MacroAssembler.h 2015-11-20 22:31:19 UTC (rev 192699)
@@ -1301,6 +1301,61 @@
#endif // !CPU(X86_64)
+ template<typename LeftType, typename RightType>
+ void moveDoubleConditionally32(RelationalCondition cond, LeftType left, RightType right, FPRegisterID src, FPRegisterID dest)
+ {
+ Jump falseCase = branch32(invert(cond), left, right);
+ moveDouble(src, dest);
+ falseCase.link(this);
+ }
+
+ template<typename LeftType, typename RightType>
+ void moveDoubleConditionally64(RelationalCondition cond, LeftType left, RightType right, FPRegisterID src, FPRegisterID dest)
+ {
+ Jump falseCase = branch64(invert(cond), left, right);
+ moveDouble(src, dest);
+ falseCase.link(this);
+ }
+
+ template<typename TestType, typename MaskType>
+ void moveDoubleConditionallyTest32(ResultCondition cond, TestType test, MaskType mask, FPRegisterID src, FPRegisterID dest)
+ {
+ if (isInvertible(cond)) {
+ Jump falseCase = branchTest32(invert(cond), test, mask);
+ moveDouble(src, dest);
+ falseCase.link(this);
+ }
+
+ Jump trueCase = branchTest32(cond, test, mask);
+ Jump falseCase = jump();
+ trueCase.link(this);
+ moveDouble(src, dest);
+ falseCase.link(this);
+ }
+
+ template<typename TestType, typename MaskType>
+ void moveDoubleConditionallyTest64(ResultCondition cond, TestType test, MaskType mask, FPRegisterID src, FPRegisterID dest)
+ {
+ if (isInvertible(cond)) {
+ Jump falseCase = branchTest64(invert(cond), test, mask);
+ moveDouble(src, dest);
+ falseCase.link(this);
+ }
+
+ Jump trueCase = branchTest64(cond, test, mask);
+ Jump falseCase = jump();
+ trueCase.link(this);
+ moveDouble(src, dest);
+ falseCase.link(this);
+ }
+
+ void moveDoubleConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID src, FPRegisterID dest)
+ {
+ Jump falseCase = branchDouble(invert(cond), left, right);
+ moveDouble(src, dest);
+ falseCase.link(this);
+ }
+
void lea(Address address, RegisterID dest)
{
addPtr(TrustedImm32(address.offset), address.base, dest);
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (192698 => 192699)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2015-11-20 22:31:19 UTC (rev 192699)
@@ -1091,18 +1091,6 @@
m_assembler.movq_i64r(imm.m_value, dest);
}
- void moveConditionally(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
- {
- m_assembler.cmpq_rr(right, left);
- m_assembler.cmovq_rr(x86Condition(cond), src, dest);
- }
-
- void moveConditionallyTest(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
- {
- m_assembler.testq_rr(testReg, mask);
- m_assembler.cmovq_rr(x86Condition(cond), src, dest);
- }
-
void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
{
ASSERT(isSSE2Present());
@@ -1171,18 +1159,6 @@
m_assembler.movl_i32r(imm.asIntptr(), dest);
}
- void moveConditionally(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
- {
- m_assembler.cmpl_rr(right, left);
- m_assembler.cmovl_rr(x86Condition(cond), src, dest);
- }
-
- void moveConditionallyTest(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
- {
- m_assembler.testl_rr(testReg, mask);
- m_assembler.cmovl_rr(x86Condition(cond), src, dest);
- }
-
void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
{
ASSERT(isSSE2Present());
@@ -1236,7 +1212,25 @@
}
#endif
+ void moveConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
+ {
+ m_assembler.cmpl_rr(right, left);
+ cmov(x86Condition(cond), src, dest);
+ }
+ void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
+ {
+ m_assembler.testl_rr(testReg, mask);
+ cmov(x86Condition(cond), src, dest);
+ }
+
+ void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID src, RegisterID dest)
+ {
+ test32(cond, testReg, mask);
+ cmov(x86Condition(cond), src, dest);
+ }
+
+
// Forwards / external control flow operations:
//
// This set of jump and conditional branch operations return a Jump
@@ -1684,6 +1678,15 @@
m_assembler.movzbl_rr(dest, dest);
}
+ void cmov(X86Assembler::Condition cond, RegisterID src, RegisterID dest)
+ {
+#if CPU(X86_64)
+ m_assembler.cmovq_rr(cond, src, dest);
+#else
+ m_assembler.cmovl_rr(cond, src, dest);
+#endif
+ }
+
private:
// Only MacroAssemblerX86 should be using the following method; SSE2 is always available on
// x86_64, and clients & subclasses of MacroAssembler should be using 'supportsFloatingPoint()'.
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h (192698 => 192699)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h 2015-11-20 22:31:19 UTC (rev 192699)
@@ -837,6 +837,30 @@
return Jump(m_assembler.jCC(x86Condition(cond)));
}
+ void moveConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
+ {
+ m_assembler.cmpq_rr(right, left);
+ cmov(x86Condition(cond), src, dest);
+ }
+
+ void moveConditionallyTest64(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
+ {
+ m_assembler.testq_rr(testReg, mask);
+ cmov(x86Condition(cond), src, dest);
+ }
+
+ void moveConditionallyTest64(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID src, RegisterID dest)
+ {
+ // if we are only interested in the low seven bits, this can be tested with a testb
+ if (mask.m_value == -1)
+ m_assembler.testq_rr(testReg, testReg);
+ else if ((mask.m_value & ~0x7f) == 0)
+ m_assembler.testb_i8r(mask.m_value, testReg);
+ else
+ m_assembler.testq_i32r(mask.m_value, testReg);
+ cmov(x86Condition(cond), src, dest);
+ }
+
void abortWithReason(AbortReason reason)
{
move(TrustedImm32(reason), X86Registers::r11);
Modified: trunk/Source/_javascript_Core/assembler/X86Assembler.h (192698 => 192699)
--- trunk/Source/_javascript_Core/assembler/X86Assembler.h 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/assembler/X86Assembler.h 2015-11-20 22:31:19 UTC (rev 192699)
@@ -1650,7 +1650,7 @@
void cmovl_rr(Condition cond, RegisterID src, RegisterID dst)
{
- m_formatter.twoByteOp(cmovcc(cond), src, dst);
+ m_formatter.twoByteOp(cmovcc(cond), dst, src);
}
void cmovl_mr(Condition cond, int offset, RegisterID base, RegisterID dst)
@@ -1665,28 +1665,28 @@
void cmovel_rr(RegisterID src, RegisterID dst)
{
- m_formatter.twoByteOp(cmovcc(ConditionE), src, dst);
+ m_formatter.twoByteOp(cmovcc(ConditionE), dst, src);
}
void cmovnel_rr(RegisterID src, RegisterID dst)
{
- m_formatter.twoByteOp(cmovcc(ConditionNE), src, dst);
+ m_formatter.twoByteOp(cmovcc(ConditionNE), dst, src);
}
void cmovpl_rr(RegisterID src, RegisterID dst)
{
- m_formatter.twoByteOp(cmovcc(ConditionP), src, dst);
+ m_formatter.twoByteOp(cmovcc(ConditionP), dst, src);
}
void cmovnpl_rr(RegisterID src, RegisterID dst)
{
- m_formatter.twoByteOp(cmovcc(ConditionNP), src, dst);
+ m_formatter.twoByteOp(cmovcc(ConditionNP), dst, src);
}
#if CPU(X86_64)
void cmovq_rr(Condition cond, RegisterID src, RegisterID dst)
{
- m_formatter.twoByteOp64(cmovcc(cond), src, dst);
+ m_formatter.twoByteOp64(cmovcc(cond), dst, src);
}
void cmovq_mr(Condition cond, int offset, RegisterID base, RegisterID dst)
@@ -1701,22 +1701,22 @@
void cmoveq_rr(RegisterID src, RegisterID dst)
{
- m_formatter.twoByteOp64(cmovcc(ConditionE), src, dst);
+ m_formatter.twoByteOp64(cmovcc(ConditionE), dst, src);
}
void cmovneq_rr(RegisterID src, RegisterID dst)
{
- m_formatter.twoByteOp64(cmovcc(ConditionNE), src, dst);
+ m_formatter.twoByteOp64(cmovcc(ConditionNE), dst, src);
}
void cmovpq_rr(RegisterID src, RegisterID dst)
{
- m_formatter.twoByteOp64(cmovcc(ConditionP), src, dst);
+ m_formatter.twoByteOp64(cmovcc(ConditionP), dst, src);
}
void cmovnpq_rr(RegisterID src, RegisterID dst)
{
- m_formatter.twoByteOp64(cmovcc(ConditionNP), src, dst);
+ m_formatter.twoByteOp64(cmovcc(ConditionNP), dst, src);
}
#else
void cmovl_mr(Condition cond, const void* addr, RegisterID dst)
Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2015-11-20 22:31:19 UTC (rev 192699)
@@ -1185,6 +1185,82 @@
inverted);
}
+ struct MoveConditionallyConfig {
+ Air::Opcode moveConditionally32;
+ Air::Opcode moveConditionally64;
+ Air::Opcode moveConditionallyTest32;
+ Air::Opcode moveConditionallyTest64;
+ Air::Opcode moveConditionallyDouble;
+ Tmp source;
+ Tmp destination;
+ };
+ Inst createSelect(Value* value, const MoveConditionallyConfig& config, bool inverted = false)
+ {
+ return createGenericCompare(
+ value,
+ [&] (
+ Arg::Width width, const Arg& relCond,
+ const ArgPromise& left, const ArgPromise& right) -> Inst {
+ switch (width) {
+ case Arg::Width8:
+ // FIXME: Support these things.
+ // https://bugs.webkit.org/show_bug.cgi?id=151504
+ return Inst();
+ case Arg::Width16:
+ return Inst();
+ case Arg::Width32:
+ if (isValidForm(config.moveConditionally32, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+ return Inst(
+ config.moveConditionally32, m_value, relCond,
+ left.consume(*this), right.consume(*this), config.source, config.destination);
+ }
+ return Inst();
+ case Arg::Width64:
+ if (isValidForm(config.moveConditionally64, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+ return Inst(
+ config.moveConditionally64, m_value, relCond,
+ left.consume(*this), right.consume(*this), config.source, config.destination);
+ }
+ return Inst();
+ }
+ },
+ [&] (
+ Arg::Width width, const Arg& resCond,
+ const ArgPromise& left, const ArgPromise& right) -> Inst {
+ switch (width) {
+ case Arg::Width8:
+ // FIXME: Support more things.
+ // https://bugs.webkit.org/show_bug.cgi?id=151504
+ return Inst();
+ case Arg::Width16:
+ return Inst();
+ case Arg::Width32:
+ if (isValidForm(config.moveConditionallyTest32, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+ return Inst(
+ config.moveConditionallyTest32, m_value, resCond,
+ left.consume(*this), right.consume(*this), config.source, config.destination);
+ }
+ return Inst();
+ case Arg::Width64:
+ if (isValidForm(config.moveConditionallyTest64, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+ return Inst(
+ config.moveConditionallyTest64, m_value, resCond,
+ left.consume(*this), right.consume(*this), config.source, config.destination);
+ }
+ return Inst();
+ }
+ },
+ [&] (Arg doubleCond, const ArgPromise& left, const ArgPromise& right) -> Inst {
+ if (isValidForm(config.moveConditionallyDouble, Arg::DoubleCond, left.kind(), right.kind(), Arg::Tmp, Arg::Tmp)) {
+ return Inst(
+ config.moveConditionallyDouble, m_value, doubleCond,
+ left.consume(*this), right.consume(*this), config.source, config.destination);
+ }
+ return Inst();
+ },
+ inverted);
+ }
+
template<typename BankInfo>
Arg marshallCCallArgument(unsigned& argumentCount, unsigned& stackCount, Value* child)
{
@@ -1470,6 +1546,33 @@
return;
}
+ case Select: {
+ Tmp result = tmp(m_value);
+ append(relaxedMoveForType(m_value->type()), tmp(m_value->child(2)), result);
+
+ MoveConditionallyConfig config;
+ config.source = tmp(m_value->child(1));
+ config.destination = result;
+
+ if (isInt(m_value->type())) {
+ config.moveConditionally32 = MoveConditionally32;
+ config.moveConditionally64 = MoveConditionally64;
+ config.moveConditionallyTest32 = MoveConditionallyTest32;
+ config.moveConditionallyTest64 = MoveConditionallyTest64;
+ config.moveConditionallyDouble = MoveConditionallyDouble;
+ } else {
+ // FIXME: it's not obvious that these are particularly efficient.
+ config.moveConditionally32 = MoveDoubleConditionally32;
+ config.moveConditionally64 = MoveDoubleConditionally64;
+ config.moveConditionallyTest32 = MoveDoubleConditionallyTest32;
+ config.moveConditionallyTest64 = MoveDoubleConditionallyTest64;
+ config.moveConditionallyDouble = MoveDoubleConditionallyDouble;
+ }
+
+ m_insts.last().append(createSelect(m_value->child(0), config));
+ return;
+ }
+
case IToD: {
appendUnOp<ConvertInt32ToDouble, ConvertInt64ToDouble, Air::Oops>(m_value->child(0));
return;
Modified: trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp 2015-11-20 22:31:19 UTC (rev 192699)
@@ -51,8 +51,10 @@
void run()
{
// Eventually this phase will do smart things. For now, it uses a super simple heuristic: it
- // places large constants in the block that uses them, and makes sure that each block has
- // only one materialization for each large constant.
+ // places constants in the block that uses them, and makes sure that each block has only one
+ // materialization for each constant. Note that this mostly only matters for large constants, since
+ // small constants get fused into the instructions that use them. But it might matter for small
+ // constants if they are used in instructions that don't do immediates, like conditional moves.
// FIXME: Implement a better story for constants. At a minimum this should allow the B3
// client to specify important constants that always get hoisted. Also, the table used to
@@ -147,16 +149,7 @@
bool needsMotion(const Value* value)
{
- if (!value->isConstant())
- return false;
-
- // We currently assume that 32-bit int constants are always cheap to materialize.
- // This is wrong for ARM. We need some abstract query like "isImmediate(int64_t)". On
- // ARM64 this would take into account the way that ARM64 can encode large constants.
- if (value->hasInt() && value->representableAs<int32_t>())
- return false;
-
- return true;
+ return value->isConstant();
}
static ValueKey doubleZero()
Modified: trunk/Source/_javascript_Core/b3/B3Opcode.cpp (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3Opcode.cpp 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.cpp 2015-11-20 22:31:19 UTC (rev 192699)
@@ -194,6 +194,9 @@
case BelowEqual:
out.print("BelowEqual");
return;
+ case Select:
+ out.print("Select");
+ return;
case Load8Z:
out.print("Load8Z");
return;
Modified: trunk/Source/_javascript_Core/b3/B3Opcode.h (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3Opcode.h 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.h 2015-11-20 22:31:19 UTC (rev 192699)
@@ -114,6 +114,10 @@
AboveEqual,
BelowEqual,
+ // SSA form of conditional move. The first child is evaluated for truthiness. If true, the second child
+ // is returned. Otherwise, the third child is returned.
+ Select,
+
// Memory loads. Opcode indicates how we load and the loaded type. These use MemoryValue.
// These return Int32:
Load8Z,
Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2015-11-20 22:31:19 UTC (rev 192699)
@@ -541,6 +541,45 @@
}
break;
+ case Select:
+ // Turn this: Select(constant, a, b)
+ // Into this: constant ? a : b
+ if (m_value->child(0)->hasInt32()) {
+ m_value->replaceWithIdentity(
+ m_value->child(0)->asInt32() ? m_value->child(1) : m_value->child(2));
+ m_changed = true;
+ break;
+ }
+
+ // Turn this: Select(Equal(x, 0), a, b)
+ // Into this: Select(x, b, a)
+ if (m_value->child(0)->opcode() == Equal && m_value->child(0)->child(1)->isInt(0)) {
+ m_value->child(0) = m_value->child(0)->child(0);
+ std::swap(m_value->child(1), m_value->child(2));
+ m_changed = true;
+ break;
+ }
+
+ // Turn this: Select(BitXor(bool, 1), a, b)
+ // Into this: Select(bool, b, a)
+ if (m_value->child(0)->opcode() == BitXor
+ && m_value->child(0)->child(1)->isInt32(1)
+ && m_value->child(0)->child(0)->returnsBool()) {
+ m_value->child(0) = m_value->child(0)->child(0);
+ std::swap(m_value->child(1), m_value->child(2));
+ m_changed = true;
+ break;
+ }
+
+ // Turn this: Select(stuff, x, x)
+ // Into this: x
+ if (m_value->child(1) == m_value->child(2)) {
+ m_value->replaceWithIdentity(m_value->child(1));
+ m_changed = true;
+ break;
+ }
+ break;
+
case Load8Z:
case Load8S:
case Load16Z:
Modified: trunk/Source/_javascript_Core/b3/B3Validate.cpp (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3Validate.cpp 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3Validate.cpp 2015-11-20 22:31:19 UTC (rev 192699)
@@ -231,6 +231,12 @@
VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
VALIDATE(value->type() == Int32, ("At ", *value));
break;
+ case Select:
+ VALIDATE(value->numChildren() == 3, ("At ", *value));
+ VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
+ VALIDATE(value->type() == value->child(1)->type(), ("At ", *value));
+ VALIDATE(value->type() == value->child(2)->type(), ("At ", *value));
+ break;
case Load8Z:
case Load8S:
case Load16Z:
Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3Value.cpp 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp 2015-11-20 22:31:19 UTC (rev 192699)
@@ -344,6 +344,7 @@
case Below:
case AboveEqual:
case BelowEqual:
+ case Select:
break;
case Div:
result.controlDependent = true;
@@ -433,6 +434,8 @@
case CheckSub:
case CheckMul:
return ValueKey(opcode(), type(), child(0), child(1));
+ case Select:
+ return ValueKey(opcode(), type(), child(0), child(1), child(2));
case Const32:
return ValueKey(Const32, type(), static_cast<int64_t>(asInt32()));
case Const64:
@@ -477,7 +480,7 @@
}
#endif // !ASSERT_DISABLED
-Type Value::typeFor(Opcode opcode, Value* firstChild)
+Type Value::typeFor(Opcode opcode, Value* firstChild, Value* secondChild)
{
switch (opcode) {
case Identity:
@@ -529,6 +532,9 @@
return Void;
case Nop:
return Void;
+ case Select:
+ ASSERT(secondChild);
+ return secondChild->type();
default:
RELEASE_ASSERT_NOT_REACHED();
}
Modified: trunk/Source/_javascript_Core/b3/B3Value.h (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3Value.h 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3Value.h 2015-11-20 22:31:19 UTC (rev 192699)
@@ -230,14 +230,24 @@
}
// This form is for those opcodes that can infer their type from the opcode and first child:
template<typename... Arguments>
- explicit Value(unsigned index, CheckedOpcodeTag, Opcode opcode, Origin origin, Value* firstChild, Arguments... arguments)
+ explicit Value(unsigned index, CheckedOpcodeTag, Opcode opcode, Origin origin, Value* firstChild)
: m_index(index)
, m_opcode(opcode)
, m_type(typeFor(opcode, firstChild))
, m_origin(origin)
- , m_children{ firstChild, arguments... }
+ , m_children{ firstChild }
{
}
+ // This form is for those opcodes that can infer their type from the opcode and first and second child:
+ template<typename... Arguments>
+ explicit Value(unsigned index, CheckedOpcodeTag, Opcode opcode, Origin origin, Value* firstChild, Value* secondChild, Arguments... arguments)
+ : m_index(index)
+ , m_opcode(opcode)
+ , m_type(typeFor(opcode, firstChild, secondChild))
+ , m_origin(origin)
+ , m_children{ firstChild, secondChild, arguments... }
+ {
+ }
// This form is for those opcodes that can infer their type from the opcode alone, and that don't
// take any arguments:
explicit Value(unsigned index, CheckedOpcodeTag, Opcode opcode, Origin origin)
@@ -277,7 +287,7 @@
private:
friend class CheckValue; // CheckValue::convertToAdd() modifies m_opcode.
- static Type typeFor(Opcode, Value* firstChild);
+ static Type typeFor(Opcode, Value* firstChild, Value* secondChild = nullptr);
// This group of fields is arranged to fit in 64 bits.
unsigned m_index;
Modified: trunk/Source/_javascript_Core/b3/B3ValueKey.cpp (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3ValueKey.cpp 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3ValueKey.cpp 2015-11-20 22:31:19 UTC (rev 192699)
@@ -37,7 +37,7 @@
void ValueKey::dump(PrintStream& out) const
{
- out.print(m_type, " ", m_opcode, "(", u.indices[0], ", ", u.indices[1], ")");
+ out.print(m_type, " ", m_opcode, "(", u.indices[0], ", ", u.indices[1], ", ", u.indices[2], ")");
}
Value* ValueKey::materialize(Procedure& proc, Origin origin) const
@@ -77,6 +77,8 @@
case BelowEqual:
case Div:
return proc.add<Value>(opcode(), type(), origin, child(proc, 0), child(proc, 1));
+ case Select:
+ return proc.add<Value>(opcode(), type(), origin, child(proc, 0), child(proc, 1), child(proc, 2));
case Const32:
return proc.add<Const32Value>(origin, static_cast<int32_t>(value()));
case Const64:
Modified: trunk/Source/_javascript_Core/b3/B3ValueKey.h (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3ValueKey.h 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3ValueKey.h 2015-11-20 22:31:19 UTC (rev 192699)
@@ -62,6 +62,8 @@
ValueKey(Opcode, Type, Value* left, Value* right);
+ ValueKey(Opcode, Type, Value* a, Value* b, Value* c);
+
ValueKey(Opcode opcode, Type type, int64_t value)
: m_opcode(opcode)
, m_type(type)
@@ -97,7 +99,7 @@
unsigned hash() const
{
- return m_opcode + m_type + WTF::IntHash<int64_t>::hash(u.value);
+ return m_opcode + m_type + WTF::IntHash<int32_t>::hash(u.indices[0]) + u.indices[1] + u.indices[2];
}
explicit operator bool() const { return *this != ValueKey(); }
@@ -137,18 +139,22 @@
Opcode m_opcode { Oops };
Type m_type { Void };
union U {
- unsigned indices[2];
+ unsigned indices[3];
int64_t value;
double doubleValue;
U()
{
- value = 0;
+ indices[0] = 0;
+ indices[1] = 0;
+ indices[2] = 0;
}
bool operator==(const U& other) const
{
- return value == other.value;
+ return indices[0] == other.indices[0]
+ && indices[1] == other.indices[1]
+ && indices[2] == other.indices[2];
}
} u;
};
Modified: trunk/Source/_javascript_Core/b3/B3ValueKeyInlines.h (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/B3ValueKeyInlines.h 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/B3ValueKeyInlines.h 2015-11-20 22:31:19 UTC (rev 192699)
@@ -49,6 +49,15 @@
u.indices[1] = right->index();
}
+inline ValueKey::ValueKey(Opcode opcode, Type type, Value* a, Value* b, Value* c)
+ : m_opcode(opcode)
+ , m_type(type)
+{
+ u.indices[0] = a->index();
+ u.indices[1] = b->index();
+ u.indices[2] = c->index();
+}
+
inline Value* ValueKey::child(Procedure& proc, unsigned index) const
{
return proc.values()[index];
Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2015-11-20 22:31:19 UTC (rev 192699)
@@ -364,6 +364,40 @@
BranchNeg64 U:G, UD:G /branch
ResCond, Tmp
+MoveConditionally32 U:G, U:G, U:G, U:G, UD:G
+ RelCond, Tmp, Tmp, Tmp, Tmp
+
+MoveConditionally64 U:G, U:G, U:G, U:G, UD:G
+ RelCond, Tmp, Tmp, Tmp, Tmp
+
+MoveConditionallyTest32 U:G, U:G, U:G, U:G, UD:G
+ ResCond, Tmp, Tmp, Tmp, Tmp
+ ResCond, Tmp, Imm, Tmp, Tmp
+
+MoveConditionallyTest64 U:G, U:G, U:G, U:G, UD:G
+ ResCond, Tmp, Tmp, Tmp, Tmp
+ ResCond, Tmp, Imm, Tmp, Tmp
+
+MoveConditionallyDouble U:G, U:F, U:F, U:G, UD:G
+ DoubleCond, Tmp, Tmp, Tmp, Tmp
+
+MoveDoubleConditionally32 U:G, U:G, U:G, U:F, UD:F
+ RelCond, Tmp, Tmp, Tmp, Tmp
+
+MoveDoubleConditionally64 U:G, U:G, U:G, U:F, UD:F
+ RelCond, Tmp, Tmp, Tmp, Tmp
+
+MoveDoubleConditionallyTest32 U:G, U:G, U:G, U:F, UD:F
+ ResCond, Tmp, Tmp, Tmp, Tmp
+ ResCond, Tmp, Imm, Tmp, Tmp
+
+MoveDoubleConditionallyTest64 U:G, U:G, U:G, U:F, UD:F
+ ResCond, Tmp, Tmp, Tmp, Tmp
+ ResCond, Tmp, Imm, Tmp, Tmp
+
+MoveDoubleConditionallyDouble U:G, U:F, U:F, U:F, UD:F
+ DoubleCond, Tmp, Tmp, Tmp, Tmp
+
Jump /branch
Ret /terminal
Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (192698 => 192699)
--- trunk/Source/_javascript_Core/b3/testb3.cpp 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp 2015-11-20 22:31:19 UTC (rev 192699)
@@ -4886,6 +4886,179 @@
CHECK(compileAndRun<int32_t>(proc, value) == value);
}
+void testBasicSelect()
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(
+ proc, Select, Origin(),
+ root->appendNew<Value>(
+ proc, Equal, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+ root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+
+ auto code = compile(proc);
+ CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1);
+ CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462);
+ CHECK(invoke<intptr_t>(*code, 43, 1, 2) == 2);
+ CHECK(invoke<intptr_t>(*code, 43, 642462, 32533) == 32533);
+}
+
+void testSelectTest()
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(
+ proc, Select, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+
+ auto code = compile(proc);
+ CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1);
+ CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462);
+ CHECK(invoke<intptr_t>(*code, 0, 1, 2) == 2);
+ CHECK(invoke<intptr_t>(*code, 0, 642462, 32533) == 32533);
+}
+
+void testSelectCompareDouble()
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(
+ proc, Select, Origin(),
+ root->appendNew<Value>(
+ proc, LessThan, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+
+ auto code = compile(proc);
+ CHECK(invoke<intptr_t>(*code, -1.0, 1.0, 1, 2) == 1);
+ CHECK(invoke<intptr_t>(*code, 42.5, 42.51, 642462, 32533) == 642462);
+ CHECK(invoke<intptr_t>(*code, PNaN, 0.0, 1, 2) == 2);
+ CHECK(invoke<intptr_t>(*code, 42.51, 42.5, 642462, 32533) == 32533);
+ CHECK(invoke<intptr_t>(*code, 42.52, 42.52, 524978245, 352) == 352);
+}
+
+void testSelectDouble()
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(
+ proc, Select, Origin(),
+ root->appendNew<Value>(
+ proc, Equal, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+ root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
+
+ auto code = compile(proc);
+ CHECK(invoke<double>(*code, 42, 1.5, 2.6) == 1.5);
+ CHECK(invoke<double>(*code, 42, 642462.7, 32533.8) == 642462.7);
+ CHECK(invoke<double>(*code, 43, 1.9, 2.0) == 2.0);
+ CHECK(invoke<double>(*code, 43, 642462.1, 32533.2) == 32533.2);
+}
+
+void testSelectDoubleTest()
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(
+ proc, Select, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
+
+ auto code = compile(proc);
+ CHECK(invoke<double>(*code, 42, 1.5, 2.6) == 1.5);
+ CHECK(invoke<double>(*code, 42, 642462.7, 32533.8) == 642462.7);
+ CHECK(invoke<double>(*code, 0, 1.9, 2.0) == 2.0);
+ CHECK(invoke<double>(*code, 0, 642462.1, 32533.2) == 32533.2);
+}
+
+void testSelectDoubleCompareDouble()
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(
+ proc, Select, Origin(),
+ root->appendNew<Value>(
+ proc, LessThan, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3)));
+
+ auto code = compile(proc);
+ CHECK(invoke<double>(*code, -1.0, 1.0, 1.1, 2.2) == 1.1);
+ CHECK(invoke<double>(*code, 42.5, 42.51, 642462.3, 32533.4) == 642462.3);
+ CHECK(invoke<double>(*code, PNaN, 0.0, 1.5, 2.6) == 2.6);
+ CHECK(invoke<double>(*code, 42.51, 42.5, 642462.7, 32533.8) == 32533.8);
+ CHECK(invoke<double>(*code, 42.52, 42.52, 524978245.9, 352.0) == 352.0);
+}
+
+void testSelectFold(intptr_t value)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(
+ proc, Select, Origin(),
+ root->appendNew<Value>(
+ proc, Equal, Origin(),
+ root->appendNew<ConstPtrValue>(proc, Origin(), value),
+ root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+
+ auto code = compile(proc);
+ CHECK(invoke<intptr_t>(*code, 1, 2) == (value == 42 ? 1 : 2));
+ CHECK(invoke<intptr_t>(*code, 642462, 32533) == (value == 42 ? 642462 : 32533));
+}
+
+void testSelectInvert()
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(
+ proc, Select, Origin(),
+ root->appendNew<Value>(
+ proc, Equal, Origin(),
+ root->appendNew<Value>(
+ proc, NotEqual, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+ root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
+ root->appendNew<Const32Value>(proc, Origin(), 0)),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+
+ auto code = compile(proc);
+ CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1);
+ CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462);
+ CHECK(invoke<intptr_t>(*code, 43, 1, 2) == 2);
+ CHECK(invoke<intptr_t>(*code, 43, 642462, 32533) == 32533);
+}
+
// Make sure the compiler does not try to optimize anything out.
NEVER_INLINE double zero()
{
@@ -5696,6 +5869,16 @@
RUN(testTruncSExt32(1000000000ll));
RUN(testTruncSExt32(-1000000000ll));
+ RUN(testBasicSelect());
+ RUN(testSelectTest());
+ RUN(testSelectCompareDouble());
+ RUN(testSelectDouble());
+ RUN(testSelectDoubleTest());
+ RUN(testSelectDoubleCompareDouble());
+ RUN(testSelectFold(42));
+ RUN(testSelectFold(43));
+ RUN(testSelectInvert());
+
if (tasks.isEmpty())
usage();
Modified: trunk/Source/_javascript_Core/ftl/FTLAbstractHeap.cpp (192698 => 192699)
--- trunk/Source/_javascript_Core/ftl/FTLAbstractHeap.cpp 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/ftl/FTLAbstractHeap.cpp 2015-11-20 22:31:19 UTC (rev 192699)
@@ -82,8 +82,10 @@
, m_heapNameLength(strlen(heapName))
, m_offset(offset)
, m_elementSize(elementSize)
+#if !FTL_USES_B3
, m_scaleTerm(0)
, m_canShift(false)
+#endif
{
#if FTL_USES_B3
UNUSED_PARAM(context);
@@ -112,7 +114,10 @@
{
if (indexAsConstant.isInt32())
return out.address(base, at(indexAsConstant.asInt32()), offset);
-
+
+#if FTL_USES_B3
+ LValue result = out.add(base, out.mul(index, out.constIntPtr(m_elementSize)));
+#else
LValue result;
if (m_canShift) {
if (!m_scaleTerm)
@@ -121,6 +126,7 @@
result = out.add(base, out.shl(index, m_scaleTerm));
} else
result = out.add(base, out.mul(index, m_scaleTerm));
+#endif
return TypedPointer(atAnyIndex(), out.addPtr(result, m_offset + offset));
}
Modified: trunk/Source/_javascript_Core/ftl/FTLAbstractHeap.h (192698 => 192699)
--- trunk/Source/_javascript_Core/ftl/FTLAbstractHeap.h 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/ftl/FTLAbstractHeap.h 2015-11-20 22:31:19 UTC (rev 192699)
@@ -188,8 +188,10 @@
size_t m_heapNameLength;
ptrdiff_t m_offset;
size_t m_elementSize;
+#if !FTL_USES_B3
LValue m_scaleTerm;
bool m_canShift;
+#endif
std::array<AbstractField, 16> m_smallIndices;
struct WithoutZeroOrOneHashTraits : WTF::GenericHashTraits<ptrdiff_t> {
Modified: trunk/Source/_javascript_Core/ftl/FTLB3Output.h (192698 => 192699)
--- trunk/Source/_javascript_Core/ftl/FTLB3Output.h 2015-11-20 22:14:56 UTC (rev 192698)
+++ trunk/Source/_javascript_Core/ftl/FTLB3Output.h 2015-11-20 22:31:19 UTC (rev 192699)
@@ -185,7 +185,11 @@
LValue unsignedToFP(LValue value, LType type) { CRASH(); }
LValue unsignedToDouble(LValue value) { CRASH(); }
LValue intCast(LValue value, LType type) { CRASH(); }
- LValue castToInt32(LValue value) { return m_block->appendNew<B3::Value>(m_proc, B3::Trunc, origin(), value); }
+ LValue castToInt32(LValue value)
+ {
+ return value->type() == B3::Int32 ? value :
+ m_block->appendNew<B3::Value>(m_proc, B3::Trunc, origin(), value);
+ }
LValue fpCast(LValue value, LType type) { CRASH(); }
LValue intToPtr(LValue value, LType type) { CRASH(); }
LValue ptrToInt(LValue value, LType type) { CRASH(); }
@@ -344,7 +348,7 @@
LValue testIsZeroPtr(LValue value, LValue mask) { return isNull(bitAnd(value, mask)); }
LValue testNonZeroPtr(LValue value, LValue mask) { return notNull(bitAnd(value, mask)); }
- LValue select(LValue value, LValue taken, LValue notTaken) { CRASH(); }
+ LValue select(LValue value, LValue taken, LValue notTaken) { return m_block->appendNew<B3::Value>(m_proc, B3::Select, origin(), value, taken, notTaken); }
LValue extractValue(LValue aggVal, unsigned index) { CRASH(); }
LValue fence(LAtomicOrdering ordering = LLVMAtomicOrderingSequentiallyConsistent, SynchronizationScope scope = CrossThread) { CRASH(); }