[vm, compiler] Use immediate forms for BinaryUint32Op.
dart2js.aot.arm64 28757440 -> 28691320 (-66k) dart2js.aot.x64 28311232 -> 28310536 (-1k) dart2js.aot.rv64 27971912 -> 27955200 (-16k) dart2js.aot.arm32 27793504 -> 27775936 (-17k) TEST=vm/dart/uint32_op_imm_test Change-Id: I25e486ea1ab3b20369c0c5a5fafae5d1ea53b1c7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/388120 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
Commit Queue
parent
950f08f904
commit
889e5795bb
@@ -0,0 +1,283 @@
|
||||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import "dart:typed_data";
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void and1(Uint32List list) {
|
||||
list[0] &= 1;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void or1(Uint32List list) {
|
||||
list[0] |= 1;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void xor1(Uint32List list) {
|
||||
list[0] ^= 1;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void add1(Uint32List list) {
|
||||
list[0] += 1;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void sub1(Uint32List list) {
|
||||
list[0] -= 1;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void mul1(Uint32List list) {
|
||||
list[0] *= 1;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void and2(Uint32List list) {
|
||||
list[0] &= 2;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void or2(Uint32List list) {
|
||||
list[0] |= 2;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void xor2(Uint32List list) {
|
||||
list[0] ^= 2;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void add2(Uint32List list) {
|
||||
list[0] += 2;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void sub2(Uint32List list) {
|
||||
list[0] -= 2;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void mul2(Uint32List list) {
|
||||
list[0] *= 2;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void and7(Uint32List list) {
|
||||
list[0] &= 7;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void or7(Uint32List list) {
|
||||
list[0] |= 7;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void xor7(Uint32List list) {
|
||||
list[0] ^= 7;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void add7(Uint32List list) {
|
||||
list[0] += 7;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void sub7(Uint32List list) {
|
||||
list[0] -= 7;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void mul7(Uint32List list) {
|
||||
list[0] *= 7;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void andH(Uint32List list) {
|
||||
list[0] &= 0x7FFFFFF;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void orH(Uint32List list) {
|
||||
list[0] |= 0x7FFFFFF;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void xorH(Uint32List list) {
|
||||
list[0] ^= 0x7FFFFFF;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void addH(Uint32List list) {
|
||||
list[0] += 0x7FFFFFF;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void subH(Uint32List list) {
|
||||
list[0] -= 0x7FFFFFF;
|
||||
}
|
||||
|
||||
@pragma("vm:never-inline")
|
||||
void mulH(Uint32List list) {
|
||||
list[0] *= 0x7FFFFFF;
|
||||
}
|
||||
|
||||
expect(int observed, int expected) {
|
||||
if (observed != expected) {
|
||||
throw "0x${observed.toRadixString(16)}";
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
Uint32List u32 = Uint32List(1);
|
||||
|
||||
u32[0] = 0x12345678;
|
||||
and1(u32);
|
||||
expect(u32[0], 0);
|
||||
u32[0] = 0x87654321;
|
||||
and1(u32);
|
||||
expect(u32[0], 1);
|
||||
u32[0] = 0x12345678;
|
||||
or1(u32);
|
||||
expect(u32[0], 0x12345679);
|
||||
u32[0] = 0x87654321;
|
||||
or1(u32);
|
||||
expect(u32[0], 0x87654321);
|
||||
u32[0] = 0x12345678;
|
||||
xor1(u32);
|
||||
expect(u32[0], 0x12345679);
|
||||
u32[0] = 0x87654321;
|
||||
xor1(u32);
|
||||
expect(u32[0], 0x87654320);
|
||||
u32[0] = 0x12345678;
|
||||
add1(u32);
|
||||
expect(u32[0], 0x12345679);
|
||||
u32[0] = 0x87654321;
|
||||
add1(u32);
|
||||
expect(u32[0], 0x87654322);
|
||||
u32[0] = 0x12345678;
|
||||
sub1(u32);
|
||||
expect(u32[0], 0x12345677);
|
||||
u32[0] = 0x87654321;
|
||||
sub1(u32);
|
||||
expect(u32[0], 0x87654320);
|
||||
u32[0] = 0x12345678;
|
||||
mul1(u32);
|
||||
expect(u32[0], 0x12345678);
|
||||
u32[0] = 0x87654321;
|
||||
mul1(u32);
|
||||
expect(u32[0], 0x87654321);
|
||||
|
||||
u32[0] = 0x12345678;
|
||||
and2(u32);
|
||||
expect(u32[0], 0);
|
||||
u32[0] = 0x87654321;
|
||||
and2(u32);
|
||||
expect(u32[0], 0);
|
||||
u32[0] = 0x12345678;
|
||||
or2(u32);
|
||||
expect(u32[0], 0x1234567a);
|
||||
u32[0] = 0x87654321;
|
||||
or2(u32);
|
||||
expect(u32[0], 0x87654323);
|
||||
u32[0] = 0x12345678;
|
||||
xor2(u32);
|
||||
expect(u32[0], 0x1234567a);
|
||||
u32[0] = 0x87654321;
|
||||
xor2(u32);
|
||||
expect(u32[0], 0x87654323);
|
||||
u32[0] = 0x12345678;
|
||||
add2(u32);
|
||||
expect(u32[0], 0x1234567a);
|
||||
u32[0] = 0x87654321;
|
||||
add2(u32);
|
||||
expect(u32[0], 0x87654323);
|
||||
u32[0] = 0x12345678;
|
||||
sub2(u32);
|
||||
expect(u32[0], 0x12345676);
|
||||
u32[0] = 0x87654321;
|
||||
sub2(u32);
|
||||
expect(u32[0], 0x8765431f);
|
||||
u32[0] = 0x12345678;
|
||||
mul2(u32);
|
||||
expect(u32[0], 0x2468acf0);
|
||||
u32[0] = 0x87654321;
|
||||
mul2(u32);
|
||||
expect(u32[0], 0x0eca8642);
|
||||
|
||||
u32[0] = 0x12345678;
|
||||
and7(u32);
|
||||
expect(u32[0], 0);
|
||||
u32[0] = 0x87654321;
|
||||
and7(u32);
|
||||
expect(u32[0], 1);
|
||||
u32[0] = 0x12345678;
|
||||
or7(u32);
|
||||
expect(u32[0], 0x1234567f);
|
||||
u32[0] = 0x87654321;
|
||||
or7(u32);
|
||||
expect(u32[0], 0x87654327);
|
||||
u32[0] = 0x12345678;
|
||||
xor7(u32);
|
||||
expect(u32[0], 0x1234567f);
|
||||
u32[0] = 0x87654321;
|
||||
xor7(u32);
|
||||
expect(u32[0], 0x87654326);
|
||||
u32[0] = 0x12345678;
|
||||
add7(u32);
|
||||
expect(u32[0], 0x1234567f);
|
||||
u32[0] = 0x87654321;
|
||||
add7(u32);
|
||||
expect(u32[0], 0x87654328);
|
||||
u32[0] = 0x12345678;
|
||||
sub7(u32);
|
||||
expect(u32[0], 0x12345671);
|
||||
u32[0] = 0x87654321;
|
||||
sub7(u32);
|
||||
expect(u32[0], 0x8765431a);
|
||||
u32[0] = 0x12345678;
|
||||
mul7(u32);
|
||||
expect(u32[0], 0x7f6e5d48);
|
||||
u32[0] = 0x87654321;
|
||||
mul7(u32);
|
||||
expect(u32[0], 0xb3c4d5e7);
|
||||
|
||||
u32[0] = 0x12345678;
|
||||
andH(u32);
|
||||
expect(u32[0], 0x02345678);
|
||||
u32[0] = 0x87654321;
|
||||
andH(u32);
|
||||
expect(u32[0], 0x07654321);
|
||||
u32[0] = 0x12345678;
|
||||
orH(u32);
|
||||
expect(u32[0], 0x17ffffff);
|
||||
u32[0] = 0x87654321;
|
||||
orH(u32);
|
||||
expect(u32[0], 0x87ffffff);
|
||||
u32[0] = 0x12345678;
|
||||
xorH(u32);
|
||||
expect(u32[0], 0x15cba987);
|
||||
u32[0] = 0x87654321;
|
||||
xorH(u32);
|
||||
expect(u32[0], 0x809abcde);
|
||||
u32[0] = 0x12345678;
|
||||
addH(u32);
|
||||
expect(u32[0], 0x1a345677);
|
||||
u32[0] = 0x87654321;
|
||||
addH(u32);
|
||||
expect(u32[0], 0x8f654320);
|
||||
u32[0] = 0x12345678;
|
||||
subH(u32);
|
||||
expect(u32[0], 0x0a345679);
|
||||
u32[0] = 0x87654321;
|
||||
subH(u32);
|
||||
expect(u32[0], 0x7f654322);
|
||||
u32[0] = 0x12345678;
|
||||
mulH(u32);
|
||||
expect(u32[0], 0xadcba988);
|
||||
u32[0] = 0x87654321;
|
||||
mulH(u32);
|
||||
expect(u32[0], 0x809abcdf);
|
||||
}
|
||||
@@ -3107,6 +3107,19 @@ void Assembler::OrImmediate(Register rd,
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::XorImmediate(Register rd,
|
||||
Register rs,
|
||||
int32_t imm,
|
||||
Condition cond) {
|
||||
Operand o;
|
||||
if (Operand::CanHold(imm, &o)) {
|
||||
eor(rd, rs, Operand(o), cond);
|
||||
} else {
|
||||
LoadImmediate(TMP, imm, cond);
|
||||
eor(rd, rs, Operand(TMP), cond);
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::CompareImmediate(Register rn, int32_t value, Condition cond) {
|
||||
Operand o;
|
||||
if (Operand::CanHold(value, &o)) {
|
||||
|
||||
@@ -863,12 +863,18 @@ class Assembler : public AssemblerBase {
|
||||
void MulImmediate(Register reg,
|
||||
int32_t imm,
|
||||
OperandSize width = kFourBytes) override {
|
||||
MulImmediate(reg, reg, imm, width);
|
||||
}
|
||||
void MulImmediate(Register rd,
|
||||
Register rn,
|
||||
int32_t imm,
|
||||
OperandSize width = kFourBytes) {
|
||||
ASSERT(width == kFourBytes);
|
||||
if (Utils::IsPowerOfTwo(imm)) {
|
||||
LslImmediate(reg, Utils::ShiftForPowerOfTwo(imm));
|
||||
LslImmediate(rd, rn, Utils::ShiftForPowerOfTwo(imm));
|
||||
} else {
|
||||
LoadImmediate(TMP, imm);
|
||||
mul(reg, reg, TMP);
|
||||
mul(rd, rn, TMP);
|
||||
}
|
||||
}
|
||||
void AndImmediate(Register rd,
|
||||
@@ -913,6 +919,7 @@ class Assembler : public AssemblerBase {
|
||||
void OrImmediate(Register rd, int32_t imm, Condition cond = AL) {
|
||||
OrImmediate(rd, rd, imm, cond);
|
||||
}
|
||||
void XorImmediate(Register rd, Register rn, int32_t imm, Condition cond = AL);
|
||||
void LslImmediate(Register rd,
|
||||
Register rn,
|
||||
int32_t shift,
|
||||
|
||||
@@ -1805,15 +1805,21 @@ class Assembler : public AssemblerBase {
|
||||
void MulImmediate(Register reg,
|
||||
int64_t imm,
|
||||
OperandSize width = kEightBytes) override {
|
||||
MulImmediate(reg, reg, imm, width);
|
||||
}
|
||||
void MulImmediate(Register dest,
|
||||
Register rn,
|
||||
int64_t imm,
|
||||
OperandSize width = kEightBytes) {
|
||||
ASSERT(width == kFourBytes || width == kEightBytes);
|
||||
if (Utils::IsPowerOfTwo(imm)) {
|
||||
LslImmediate(reg, Utils::ShiftForPowerOfTwo(imm), width);
|
||||
LslImmediate(dest, rn, Utils::ShiftForPowerOfTwo(imm), width);
|
||||
} else {
|
||||
LoadImmediate(TMP, imm);
|
||||
if (width == kFourBytes) {
|
||||
mulw(reg, reg, TMP);
|
||||
mulw(dest, rn, TMP);
|
||||
} else {
|
||||
mul(reg, reg, TMP);
|
||||
mul(dest, rn, TMP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6967,37 +6967,65 @@ LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Zone* zone,
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
summary->set_in(1, Location::RequiresRegister());
|
||||
summary->set_in(1, LocationRegisterOrConstant(right()));
|
||||
summary->set_out(0, Location::RequiresRegister());
|
||||
return summary;
|
||||
}
|
||||
|
||||
void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register left = locs()->in(0).reg();
|
||||
Register right = locs()->in(1).reg();
|
||||
Register out = locs()->out(0).reg();
|
||||
Register left = locs()->in(0).reg();
|
||||
ASSERT(out != left);
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
__ and_(out, left, compiler::Operand(right));
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ orr(out, left, compiler::Operand(right));
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ eor(out, left, compiler::Operand(right));
|
||||
break;
|
||||
case Token::kADD:
|
||||
__ add(out, left, compiler::Operand(right));
|
||||
break;
|
||||
case Token::kSUB:
|
||||
__ sub(out, left, compiler::Operand(right));
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ mul(out, left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
if (locs()->in(1).IsConstant()) {
|
||||
int64_t right;
|
||||
const bool ok = compiler::HasIntegerValue(locs()->in(1).constant(), &right);
|
||||
RELEASE_ASSERT(ok);
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
__ AndImmediate(out, left, right);
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ OrImmediate(out, left, right);
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ XorImmediate(out, left, right);
|
||||
break;
|
||||
case Token::kADD:
|
||||
__ AddImmediate(out, left, right);
|
||||
break;
|
||||
case Token::kSUB:
|
||||
__ AddImmediate(out, left, -right);
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ MulImmediate(out, left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
Register right = locs()->in(1).reg();
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
__ and_(out, left, compiler::Operand(right));
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ orr(out, left, compiler::Operand(right));
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ eor(out, left, compiler::Operand(right));
|
||||
break;
|
||||
case Token::kADD:
|
||||
__ add(out, left, compiler::Operand(right));
|
||||
break;
|
||||
case Token::kSUB:
|
||||
__ sub(out, left, compiler::Operand(right));
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ mul(out, left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6019,37 +6019,65 @@ LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Zone* zone,
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
summary->set_in(1, Location::RequiresRegister());
|
||||
summary->set_in(1, LocationRegisterOrConstant(right()));
|
||||
summary->set_out(0, Location::RequiresRegister());
|
||||
return summary;
|
||||
}
|
||||
|
||||
void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register left = locs()->in(0).reg();
|
||||
Register right = locs()->in(1).reg();
|
||||
compiler::Operand r = compiler::Operand(right);
|
||||
Register out = locs()->out(0).reg();
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
__ and_(out, left, r);
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ orr(out, left, r);
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ eor(out, left, r);
|
||||
break;
|
||||
case Token::kADD:
|
||||
__ addw(out, left, r);
|
||||
break;
|
||||
case Token::kSUB:
|
||||
__ subw(out, left, r);
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ mulw(out, left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
Register left = locs()->in(0).reg();
|
||||
if (locs()->in(1).IsConstant()) {
|
||||
int64_t right;
|
||||
const bool ok = compiler::HasIntegerValue(locs()->in(1).constant(), &right);
|
||||
RELEASE_ASSERT(ok);
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
__ AndImmediate(out, left, right, compiler::kFourBytes);
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ OrImmediate(out, left, right, compiler::kFourBytes);
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ XorImmediate(out, left, right, compiler::kFourBytes);
|
||||
break;
|
||||
case Token::kADD:
|
||||
__ AddImmediate(out, left, right, compiler::kFourBytes);
|
||||
break;
|
||||
case Token::kSUB:
|
||||
__ AddImmediate(out, left, -right, compiler::kFourBytes);
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ MulImmediate(out, left, right, compiler::kFourBytes);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
Register right = locs()->in(1).reg();
|
||||
compiler::Operand r = compiler::Operand(right);
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
__ and_(out, left, r);
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ orr(out, left, r);
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ eor(out, left, r);
|
||||
break;
|
||||
case Token::kADD:
|
||||
__ addw(out, left, r);
|
||||
break;
|
||||
case Token::kSUB:
|
||||
__ subw(out, left, r);
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ mulw(out, left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6576,44 +6576,72 @@ LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Zone* zone,
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
summary->set_in(1, Location::RequiresRegister());
|
||||
summary->set_in(1, LocationRegisterOrConstant(right()));
|
||||
summary->set_out(0, Location::RequiresRegister());
|
||||
return summary;
|
||||
}
|
||||
|
||||
void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register left = locs()->in(0).reg();
|
||||
Register right = locs()->in(1).reg();
|
||||
Register out = locs()->out(0).reg();
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
__ and_(out, left, right);
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ or_(out, left, right);
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ xor_(out, left, right);
|
||||
break;
|
||||
case Token::kADD:
|
||||
Register left = locs()->in(0).reg();
|
||||
if (locs()->in(1).IsConstant()) {
|
||||
int64_t right;
|
||||
const bool ok = compiler::HasIntegerValue(locs()->in(1).constant(), &right);
|
||||
RELEASE_ASSERT(ok);
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
__ AndImmediate(out, left, right, compiler::kFourBytes);
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ OrImmediate(out, left, right, compiler::kFourBytes);
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ XorImmediate(out, left, right, compiler::kFourBytes);
|
||||
break;
|
||||
case Token::kADD:
|
||||
__ AddImmediate(out, left, right, compiler::kFourBytes);
|
||||
break;
|
||||
case Token::kSUB:
|
||||
__ AddImmediate(out, left, -right, compiler::kFourBytes);
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ MulImmediate(out, left, right, compiler::kFourBytes);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
Register right = locs()->in(1).reg();
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
__ and_(out, left, right);
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ or_(out, left, right);
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ xor_(out, left, right);
|
||||
break;
|
||||
case Token::kADD:
|
||||
#if XLEN == 32
|
||||
__ add(out, left, right);
|
||||
__ add(out, left, right);
|
||||
#elif XLEN > 32
|
||||
__ addw(out, left, right);
|
||||
__ addw(out, left, right);
|
||||
#endif
|
||||
break;
|
||||
case Token::kSUB:
|
||||
break;
|
||||
case Token::kSUB:
|
||||
#if XLEN == 32
|
||||
__ sub(out, left, right);
|
||||
__ sub(out, left, right);
|
||||
#elif XLEN > 32
|
||||
__ subw(out, left, right);
|
||||
__ subw(out, left, right);
|
||||
#endif
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ mul(out, left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ mul(out, left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6344,58 +6344,69 @@ LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Zone* zone,
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
summary->set_in(1, Location::RequiresRegister());
|
||||
summary->set_in(1, LocationRegisterOrConstant(right()));
|
||||
summary->set_out(0, Token::IsCommutativeOp(op_kind())
|
||||
? Location::SameAsFirstOrSecondInput()
|
||||
: Location::SameAsFirstInput());
|
||||
return summary;
|
||||
}
|
||||
|
||||
template <typename OperandType>
|
||||
static void EmitIntegerArithmetic(FlowGraphCompiler* compiler,
|
||||
Token::Kind op_kind,
|
||||
Register left,
|
||||
const OperandType& right) {
|
||||
switch (op_kind) {
|
||||
case Token::kADD:
|
||||
__ addl(left, right);
|
||||
break;
|
||||
case Token::kSUB:
|
||||
__ subl(left, right);
|
||||
break;
|
||||
case Token::kBIT_AND:
|
||||
__ andl(left, right);
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ orl(left, right);
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ xorl(left, right);
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ imull(left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register left = locs()->in(0).reg();
|
||||
Register right = locs()->in(1).reg();
|
||||
Register out = locs()->out(0).reg();
|
||||
Register left = locs()->in(0).reg();
|
||||
ASSERT(out == left);
|
||||
switch (op_kind()) {
|
||||
case Token::kBIT_AND:
|
||||
case Token::kBIT_OR:
|
||||
case Token::kBIT_XOR:
|
||||
case Token::kADD:
|
||||
case Token::kSUB:
|
||||
case Token::kMUL:
|
||||
EmitIntegerArithmetic(compiler, op_kind(), left, right);
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
if (locs()->in(1).IsConstant()) {
|
||||
int64_t value;
|
||||
const bool ok = compiler::HasIntegerValue(locs()->in(1).constant(), &value);
|
||||
RELEASE_ASSERT(ok);
|
||||
compiler::Immediate right =
|
||||
compiler::Immediate(static_cast<int32_t>(static_cast<uint32_t>(value)));
|
||||
switch (op_kind()) {
|
||||
case Token::kADD:
|
||||
__ addl(left, right);
|
||||
break;
|
||||
case Token::kSUB:
|
||||
__ subl(left, right);
|
||||
break;
|
||||
case Token::kBIT_AND:
|
||||
__ andl(left, right);
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ orl(left, right);
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ xorl(left, right);
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ imull(left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
Register right = locs()->in(1).reg();
|
||||
switch (op_kind()) {
|
||||
case Token::kADD:
|
||||
__ addl(left, right);
|
||||
break;
|
||||
case Token::kSUB:
|
||||
__ subl(left, right);
|
||||
break;
|
||||
case Token::kBIT_AND:
|
||||
__ andl(left, right);
|
||||
break;
|
||||
case Token::kBIT_OR:
|
||||
__ orl(left, right);
|
||||
break;
|
||||
case Token::kBIT_XOR:
|
||||
__ xorl(left, right);
|
||||
break;
|
||||
case Token::kMUL:
|
||||
__ imull(left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user