mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 21:31:20 +00:00
Reapply "[vm, arm64] Add assembler support for tbz and use it for BranchIfSmi."
Skip addition of far branch support to the test harness. Change-Id: Idec3a644e0dc4165bfaa8daa948f1aee172c1eea Reviewed-on: https://dart-review.googlesource.com/22740 Reviewed-by: Zach Anderson <zra@google.com>
This commit is contained in:
parent
28c90a272a
commit
5b9558228d
|
@ -65,6 +65,142 @@ const char* Assembler::FpuRegisterName(FpuRegister reg) {
|
||||||
return fpu_reg_names[reg];
|
return fpu_reg_names[reg];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t Assembler::BindImm19Branch(int64_t position, int64_t dest) {
|
||||||
|
if (use_far_branches() && !CanEncodeImm19BranchOffset(dest)) {
|
||||||
|
// Far branches are enabled, and we can't encode the branch offset in
|
||||||
|
// 19 bits.
|
||||||
|
|
||||||
|
// Grab the guarding branch instruction.
|
||||||
|
const int32_t guard_branch =
|
||||||
|
buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize);
|
||||||
|
|
||||||
|
// Grab the far branch instruction.
|
||||||
|
const int32_t far_branch =
|
||||||
|
buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
|
||||||
|
const Condition c = DecodeImm19BranchCondition(guard_branch);
|
||||||
|
|
||||||
|
// Grab the link to the next branch.
|
||||||
|
const int32_t next = DecodeImm26BranchOffset(far_branch);
|
||||||
|
|
||||||
|
// dest is the offset is from the guarding branch instruction.
|
||||||
|
// Correct it to be from the following instruction.
|
||||||
|
const int64_t offset = dest - Instr::kInstrSize;
|
||||||
|
|
||||||
|
// Encode the branch.
|
||||||
|
const int32_t encoded_branch = EncodeImm26BranchOffset(offset, far_branch);
|
||||||
|
|
||||||
|
// If the guard branch is conditioned on NV, replace it with a nop.
|
||||||
|
if (c == NV) {
|
||||||
|
buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize,
|
||||||
|
Instr::kNopInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the far branch into the buffer and link to the next branch.
|
||||||
|
buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, encoded_branch);
|
||||||
|
return next;
|
||||||
|
} else if (use_far_branches() && CanEncodeImm19BranchOffset(dest)) {
|
||||||
|
// We assembled a far branch, but we don't need it. Replace it with a near
|
||||||
|
// branch.
|
||||||
|
|
||||||
|
// Grab the guarding branch instruction.
|
||||||
|
const int32_t guard_branch =
|
||||||
|
buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize);
|
||||||
|
|
||||||
|
// Grab the far branch instruction.
|
||||||
|
const int32_t far_branch =
|
||||||
|
buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
|
||||||
|
|
||||||
|
// Grab the link to the next branch.
|
||||||
|
const int32_t next = DecodeImm26BranchOffset(far_branch);
|
||||||
|
|
||||||
|
// Re-target the guarding branch and flip the conditional sense.
|
||||||
|
int32_t encoded_guard_branch = EncodeImm19BranchOffset(dest, guard_branch);
|
||||||
|
const Condition c = DecodeImm19BranchCondition(encoded_guard_branch);
|
||||||
|
encoded_guard_branch =
|
||||||
|
EncodeImm19BranchCondition(InvertCondition(c), encoded_guard_branch);
|
||||||
|
|
||||||
|
// Write back the re-encoded instructions. The far branch becomes a nop.
|
||||||
|
buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize,
|
||||||
|
encoded_guard_branch);
|
||||||
|
buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize,
|
||||||
|
Instr::kNopInstruction);
|
||||||
|
return next;
|
||||||
|
} else {
|
||||||
|
const int32_t next = buffer_.Load<int32_t>(position);
|
||||||
|
const int32_t encoded = EncodeImm19BranchOffset(dest, next);
|
||||||
|
buffer_.Store<int32_t>(position, encoded);
|
||||||
|
return DecodeImm19BranchOffset(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t Assembler::BindImm14Branch(int64_t position, int64_t dest) {
|
||||||
|
if (use_far_branches() && !CanEncodeImm14BranchOffset(dest)) {
|
||||||
|
// Far branches are enabled, and we can't encode the branch offset in
|
||||||
|
// 14 bits.
|
||||||
|
|
||||||
|
// Grab the guarding branch instruction.
|
||||||
|
const int32_t guard_branch =
|
||||||
|
buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize);
|
||||||
|
|
||||||
|
// Grab the far branch instruction.
|
||||||
|
const int32_t far_branch =
|
||||||
|
buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
|
||||||
|
const Condition c = DecodeImm14BranchCondition(guard_branch);
|
||||||
|
|
||||||
|
// Grab the link to the next branch.
|
||||||
|
const int32_t next = DecodeImm26BranchOffset(far_branch);
|
||||||
|
|
||||||
|
// dest is the offset is from the guarding branch instruction.
|
||||||
|
// Correct it to be from the following instruction.
|
||||||
|
const int64_t offset = dest - Instr::kInstrSize;
|
||||||
|
|
||||||
|
// Encode the branch.
|
||||||
|
const int32_t encoded_branch = EncodeImm26BranchOffset(offset, far_branch);
|
||||||
|
|
||||||
|
// If the guard branch is conditioned on NV, replace it with a nop.
|
||||||
|
if (c == NV) {
|
||||||
|
buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize,
|
||||||
|
Instr::kNopInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the far branch into the buffer and link to the next branch.
|
||||||
|
buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, encoded_branch);
|
||||||
|
return next;
|
||||||
|
} else if (use_far_branches() && CanEncodeImm14BranchOffset(dest)) {
|
||||||
|
// We assembled a far branch, but we don't need it. Replace it with a near
|
||||||
|
// branch.
|
||||||
|
|
||||||
|
// Grab the guarding branch instruction.
|
||||||
|
const int32_t guard_branch =
|
||||||
|
buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize);
|
||||||
|
|
||||||
|
// Grab the far branch instruction.
|
||||||
|
const int32_t far_branch =
|
||||||
|
buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
|
||||||
|
|
||||||
|
// Grab the link to the next branch.
|
||||||
|
const int32_t next = DecodeImm26BranchOffset(far_branch);
|
||||||
|
|
||||||
|
// Re-target the guarding branch and flip the conditional sense.
|
||||||
|
int32_t encoded_guard_branch = EncodeImm14BranchOffset(dest, guard_branch);
|
||||||
|
const Condition c = DecodeImm14BranchCondition(encoded_guard_branch);
|
||||||
|
encoded_guard_branch =
|
||||||
|
EncodeImm14BranchCondition(InvertCondition(c), encoded_guard_branch);
|
||||||
|
|
||||||
|
// Write back the re-encoded instructions. The far branch becomes a nop.
|
||||||
|
buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize,
|
||||||
|
encoded_guard_branch);
|
||||||
|
buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize,
|
||||||
|
Instr::kNopInstruction);
|
||||||
|
return next;
|
||||||
|
} else {
|
||||||
|
const int32_t next = buffer_.Load<int32_t>(position);
|
||||||
|
const int32_t encoded = EncodeImm14BranchOffset(dest, next);
|
||||||
|
buffer_.Store<int32_t>(position, encoded);
|
||||||
|
return DecodeImm14BranchOffset(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Assembler::Bind(Label* label) {
|
void Assembler::Bind(Label* label) {
|
||||||
ASSERT(!label->IsBound());
|
ASSERT(!label->IsBound());
|
||||||
const intptr_t bound_pc = buffer_.Size();
|
const intptr_t bound_pc = buffer_.Size();
|
||||||
|
@ -72,73 +208,10 @@ void Assembler::Bind(Label* label) {
|
||||||
while (label->IsLinked()) {
|
while (label->IsLinked()) {
|
||||||
const int64_t position = label->Position();
|
const int64_t position = label->Position();
|
||||||
const int64_t dest = bound_pc - position;
|
const int64_t dest = bound_pc - position;
|
||||||
if (use_far_branches() && !CanEncodeImm19BranchOffset(dest)) {
|
if (IsTestAndBranch(buffer_.Load<int32_t>(position))) {
|
||||||
// Far branches are enabled, and we can't encode the branch offset in
|
label->position_ = BindImm14Branch(position, dest);
|
||||||
// 19 bits.
|
|
||||||
|
|
||||||
// Grab the guarding branch instruction.
|
|
||||||
const int32_t guard_branch =
|
|
||||||
buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize);
|
|
||||||
|
|
||||||
// Grab the far branch instruction.
|
|
||||||
const int32_t far_branch =
|
|
||||||
buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
|
|
||||||
|
|
||||||
const Condition c = DecodeImm19BranchCondition(guard_branch);
|
|
||||||
|
|
||||||
// Grab the link to the next branch.
|
|
||||||
const int32_t next = DecodeImm26BranchOffset(far_branch);
|
|
||||||
|
|
||||||
// dest is the offset is from the guarding branch instruction.
|
|
||||||
// Correct it to be from the following instruction.
|
|
||||||
const int64_t offset = dest - Instr::kInstrSize;
|
|
||||||
|
|
||||||
// Encode the branch.
|
|
||||||
const int32_t encoded_branch =
|
|
||||||
EncodeImm26BranchOffset(offset, far_branch);
|
|
||||||
|
|
||||||
// If the guard branch is conditioned on NV, replace it with a nop.
|
|
||||||
if (c == NV) {
|
|
||||||
buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize,
|
|
||||||
Instr::kNopInstruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the far branch into the buffer and link to the next branch.
|
|
||||||
buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, encoded_branch);
|
|
||||||
label->position_ = next;
|
|
||||||
} else if (use_far_branches() && CanEncodeImm19BranchOffset(dest)) {
|
|
||||||
// We assembled a far branch, but we don't need it. Replace it with a near
|
|
||||||
// branch.
|
|
||||||
|
|
||||||
// Grab the guarding branch instruction.
|
|
||||||
const int32_t guard_branch =
|
|
||||||
buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize);
|
|
||||||
|
|
||||||
// Grab the far branch instruction.
|
|
||||||
const int32_t far_branch =
|
|
||||||
buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
|
|
||||||
|
|
||||||
// Grab the link to the next branch.
|
|
||||||
const int32_t next = DecodeImm26BranchOffset(far_branch);
|
|
||||||
|
|
||||||
// Re-target the guarding branch and flip the conditional sense.
|
|
||||||
int32_t encoded_guard_branch =
|
|
||||||
EncodeImm19BranchOffset(dest, guard_branch);
|
|
||||||
const Condition c = DecodeImm19BranchCondition(encoded_guard_branch);
|
|
||||||
encoded_guard_branch =
|
|
||||||
EncodeImm19BranchCondition(InvertCondition(c), encoded_guard_branch);
|
|
||||||
|
|
||||||
// Write back the re-encoded instructions. The far branch becomes a nop.
|
|
||||||
buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize,
|
|
||||||
encoded_guard_branch);
|
|
||||||
buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize,
|
|
||||||
Instr::kNopInstruction);
|
|
||||||
label->position_ = next;
|
|
||||||
} else {
|
} else {
|
||||||
const int32_t next = buffer_.Load<int32_t>(position);
|
label->position_ = BindImm19Branch(position, dest);
|
||||||
const int32_t encoded = EncodeImm19BranchOffset(dest, next);
|
|
||||||
buffer_.Store<int32_t>(position, encoded);
|
|
||||||
label->position_ = DecodeImm19BranchOffset(next);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
label->BindTo(bound_pc);
|
label->BindTo(bound_pc);
|
||||||
|
|
|
@ -975,6 +975,14 @@ class Assembler : public ValueObject {
|
||||||
EmitCompareAndBranch(CBNZ, rt, label, sz);
|
EmitCompareAndBranch(CBNZ, rt, label, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test bit and branch if zero.
|
||||||
|
void tbz(Label* label, Register rt, intptr_t bit_number) {
|
||||||
|
EmitTestAndBranch(TBZ, rt, bit_number, label);
|
||||||
|
}
|
||||||
|
void tbnz(Label* label, Register rt, intptr_t bit_number) {
|
||||||
|
EmitTestAndBranch(TBNZ, rt, bit_number, label);
|
||||||
|
}
|
||||||
|
|
||||||
// Branch, link, return.
|
// Branch, link, return.
|
||||||
void br(Register rn) { EmitUnconditionalBranchRegOp(BR, rn); }
|
void br(Register rn) { EmitUnconditionalBranchRegOp(BR, rn); }
|
||||||
void blr(Register rn) { EmitUnconditionalBranchRegOp(BLR, rn); }
|
void blr(Register rn) { EmitUnconditionalBranchRegOp(BLR, rn); }
|
||||||
|
@ -1314,15 +1322,9 @@ class Assembler : public ValueObject {
|
||||||
LslImmediate(dst, src, kSmiTagSize);
|
LslImmediate(dst, src, kSmiTagSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BranchIfNotSmi(Register reg, Label* label) {
|
void BranchIfNotSmi(Register reg, Label* label) { tbnz(label, reg, kSmiTag); }
|
||||||
tsti(reg, Immediate(kSmiTagMask));
|
|
||||||
b(label, NE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BranchIfSmi(Register reg, Label* label) {
|
void BranchIfSmi(Register reg, Label* label) { tbz(label, reg, kSmiTag); }
|
||||||
tsti(reg, Immediate(kSmiTagMask));
|
|
||||||
b(label, EQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Branch(const StubEntry& stub_entry,
|
void Branch(const StubEntry& stub_entry,
|
||||||
Register pp,
|
Register pp,
|
||||||
|
@ -1683,6 +1685,9 @@ class Assembler : public ValueObject {
|
||||||
Emit(encoding);
|
Emit(encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t BindImm19Branch(int64_t position, int64_t dest);
|
||||||
|
int32_t BindImm14Branch(int64_t position, int64_t dest);
|
||||||
|
|
||||||
int32_t EncodeImm19BranchOffset(int64_t imm, int32_t instr) {
|
int32_t EncodeImm19BranchOffset(int64_t imm, int32_t instr) {
|
||||||
if (!CanEncodeImm19BranchOffset(imm)) {
|
if (!CanEncodeImm19BranchOffset(imm)) {
|
||||||
ASSERT(!use_far_branches());
|
ASSERT(!use_far_branches());
|
||||||
|
@ -1699,6 +1704,22 @@ class Assembler : public ValueObject {
|
||||||
return static_cast<int64_t>(off);
|
return static_cast<int64_t>(off);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t EncodeImm14BranchOffset(int64_t imm, int32_t instr) {
|
||||||
|
if (!CanEncodeImm14BranchOffset(imm)) {
|
||||||
|
ASSERT(!use_far_branches());
|
||||||
|
Thread::Current()->long_jump_base()->Jump(1,
|
||||||
|
Object::branch_offset_error());
|
||||||
|
}
|
||||||
|
const int32_t imm32 = static_cast<int32_t>(imm);
|
||||||
|
const int32_t off = (((imm32 >> 2) << kImm14Shift) & kImm14Mask);
|
||||||
|
return (instr & ~kImm14Mask) | off;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t DecodeImm14BranchOffset(int32_t instr) {
|
||||||
|
const int32_t off = (((instr & kImm14Mask) >> kImm14Shift) << 18) >> 16;
|
||||||
|
return static_cast<int64_t>(off);
|
||||||
|
}
|
||||||
|
|
||||||
bool IsConditionalBranch(int32_t instr) {
|
bool IsConditionalBranch(int32_t instr) {
|
||||||
return (instr & ConditionalBranchMask) ==
|
return (instr & ConditionalBranchMask) ==
|
||||||
(ConditionalBranchFixed & ConditionalBranchMask);
|
(ConditionalBranchFixed & ConditionalBranchMask);
|
||||||
|
@ -1709,6 +1730,11 @@ class Assembler : public ValueObject {
|
||||||
(CompareAndBranchFixed & CompareAndBranchMask);
|
(CompareAndBranchFixed & CompareAndBranchMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsTestAndBranch(int32_t instr) {
|
||||||
|
return (instr & TestAndBranchMask) ==
|
||||||
|
(TestAndBranchFixed & TestAndBranchMask);
|
||||||
|
}
|
||||||
|
|
||||||
Condition DecodeImm19BranchCondition(int32_t instr) {
|
Condition DecodeImm19BranchCondition(int32_t instr) {
|
||||||
if (IsConditionalBranch(instr)) {
|
if (IsConditionalBranch(instr)) {
|
||||||
return static_cast<Condition>((instr & kCondMask) >> kCondShift);
|
return static_cast<Condition>((instr & kCondMask) >> kCondShift);
|
||||||
|
@ -1726,6 +1752,16 @@ class Assembler : public ValueObject {
|
||||||
return (instr & ~B24) | (cond == EQ ? B24 : 0); // cbz : cbnz
|
return (instr & ~B24) | (cond == EQ ? B24 : 0); // cbz : cbnz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Condition DecodeImm14BranchCondition(int32_t instr) {
|
||||||
|
ASSERT(IsTestAndBranch(instr));
|
||||||
|
return (instr & B24) ? EQ : NE; // tbz : tbnz
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t EncodeImm14BranchCondition(Condition cond, int32_t instr) {
|
||||||
|
ASSERT(IsTestAndBranch(instr));
|
||||||
|
return (instr & ~B24) | (cond == EQ ? B24 : 0); // tbz : tbnz
|
||||||
|
}
|
||||||
|
|
||||||
int32_t EncodeImm26BranchOffset(int64_t imm, int32_t instr) {
|
int32_t EncodeImm26BranchOffset(int64_t imm, int32_t instr) {
|
||||||
const int32_t imm32 = static_cast<int32_t>(imm);
|
const int32_t imm32 = static_cast<int32_t>(imm);
|
||||||
const int32_t off = (((imm32 >> 2) << kImm26Shift) & kImm26Mask);
|
const int32_t off = (((imm32 >> 2) << kImm26Shift) & kImm26Mask);
|
||||||
|
@ -1750,6 +1786,21 @@ class Assembler : public ValueObject {
|
||||||
Emit(encoding);
|
Emit(encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitTestAndBranchOp(TestAndBranchOp op,
|
||||||
|
Register rt,
|
||||||
|
intptr_t bit_number,
|
||||||
|
int64_t imm) {
|
||||||
|
ASSERT((bit_number >= 0) && (bit_number <= 63));
|
||||||
|
ASSERT(Utils::IsInt(16, imm) && ((imm & 0x3) == 0));
|
||||||
|
ASSERT((rt != CSP) && (rt != R31));
|
||||||
|
const Register crt = ConcreteRegister(rt);
|
||||||
|
const int32_t encoded_offset = EncodeImm14BranchOffset(imm, 0);
|
||||||
|
const int32_t encoding = op | (static_cast<int32_t>(bit_number) << 19) |
|
||||||
|
(static_cast<int32_t>(crt) << kRtShift) |
|
||||||
|
encoded_offset;
|
||||||
|
Emit(encoding);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitConditionalBranchOp(ConditionalBranchOp op,
|
void EmitConditionalBranchOp(ConditionalBranchOp op,
|
||||||
Condition cond,
|
Condition cond,
|
||||||
int64_t imm) {
|
int64_t imm) {
|
||||||
|
@ -1764,6 +1815,11 @@ class Assembler : public ValueObject {
|
||||||
return Utils::IsInt(21, offset);
|
return Utils::IsInt(21, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CanEncodeImm14BranchOffset(int64_t offset) {
|
||||||
|
ASSERT(Utils::IsAligned(offset, 4));
|
||||||
|
return Utils::IsInt(16, offset);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitConditionalBranch(ConditionalBranchOp op,
|
void EmitConditionalBranch(ConditionalBranchOp op,
|
||||||
Condition cond,
|
Condition cond,
|
||||||
Label* label) {
|
Label* label) {
|
||||||
|
@ -1824,6 +1880,32 @@ class Assembler : public ValueObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitTestAndBranch(TestAndBranchOp op,
|
||||||
|
Register rt,
|
||||||
|
intptr_t bit_number,
|
||||||
|
Label* label) {
|
||||||
|
if (label->IsBound()) {
|
||||||
|
const int64_t dest = label->Position() - buffer_.Size();
|
||||||
|
if (use_far_branches() && !CanEncodeImm14BranchOffset(dest)) {
|
||||||
|
EmitTestAndBranchOp(op == TBZ ? TBNZ : TBZ, rt, bit_number,
|
||||||
|
2 * Instr::kInstrSize);
|
||||||
|
b(dest);
|
||||||
|
} else {
|
||||||
|
EmitTestAndBranchOp(op, rt, bit_number, dest);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const int64_t position = buffer_.Size();
|
||||||
|
if (use_far_branches()) {
|
||||||
|
EmitTestAndBranchOp(op == TBZ ? TBNZ : TBZ, rt, bit_number,
|
||||||
|
2 * Instr::kInstrSize);
|
||||||
|
b(label->position_);
|
||||||
|
} else {
|
||||||
|
EmitTestAndBranchOp(op, rt, bit_number, label->position_);
|
||||||
|
}
|
||||||
|
label->LinkTo(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CanEncodeImm26BranchOffset(int64_t offset) {
|
bool CanEncodeImm26BranchOffset(int64_t offset) {
|
||||||
ASSERT(Utils::IsAligned(offset, 4));
|
ASSERT(Utils::IsAligned(offset, 4));
|
||||||
return Utils::IsInt(26, offset);
|
return Utils::IsInt(26, offset);
|
||||||
|
|
|
@ -996,6 +996,74 @@ ASSEMBLER_TEST_RUN(CmpBranchIfNotZeroNotTaken, test) {
|
||||||
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(TstBranchIfZero, assembler) {
|
||||||
|
Label l;
|
||||||
|
|
||||||
|
__ movz(R0, Immediate(42), 0);
|
||||||
|
__ movz(R1, Immediate((0 << 5) | 1), 0);
|
||||||
|
|
||||||
|
__ tbz(&l, R1, 5);
|
||||||
|
__ movz(R0, Immediate(0), 0);
|
||||||
|
__ Bind(&l);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_RUN(TstBranchIfZero, test) {
|
||||||
|
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||||
|
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(TstBranchIfZeroNotTaken, assembler) {
|
||||||
|
Label l;
|
||||||
|
|
||||||
|
__ movz(R0, Immediate(0), 0);
|
||||||
|
__ movz(R1, Immediate((1 << 5) | 1), 0);
|
||||||
|
|
||||||
|
__ tbz(&l, R1, 5);
|
||||||
|
__ movz(R0, Immediate(42), 0);
|
||||||
|
__ Bind(&l);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_RUN(TstBranchIfZeroNotTaken, test) {
|
||||||
|
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||||
|
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(TstBranchIfNotZero, assembler) {
|
||||||
|
Label l;
|
||||||
|
|
||||||
|
__ movz(R0, Immediate(42), 0);
|
||||||
|
__ movz(R1, Immediate((1 << 5) | 1), 0);
|
||||||
|
|
||||||
|
__ tbnz(&l, R1, 5);
|
||||||
|
__ movz(R0, Immediate(0), 0);
|
||||||
|
__ Bind(&l);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_RUN(TstBranchIfNotZero, test) {
|
||||||
|
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||||
|
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(TstBranchIfNotZeroNotTaken, assembler) {
|
||||||
|
Label l;
|
||||||
|
|
||||||
|
__ movz(R0, Immediate(0), 0);
|
||||||
|
__ movz(R1, Immediate((0 << 5) | 1), 0);
|
||||||
|
|
||||||
|
__ tbnz(&l, R1, 5);
|
||||||
|
__ movz(R0, Immediate(42), 0);
|
||||||
|
__ Bind(&l);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_RUN(TstBranchIfNotZeroNotTaken, test) {
|
||||||
|
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||||
|
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||||
|
}
|
||||||
|
|
||||||
ASSEMBLER_TEST_GENERATE(FcmpEqBranch, assembler) {
|
ASSEMBLER_TEST_GENERATE(FcmpEqBranch, assembler) {
|
||||||
Label l;
|
Label l;
|
||||||
|
|
||||||
|
|
|
@ -784,6 +784,7 @@ enum InstructionFields {
|
||||||
kImm12ShiftBits = 2,
|
kImm12ShiftBits = 2,
|
||||||
kImm14Shift = 5,
|
kImm14Shift = 5,
|
||||||
kImm14Bits = 14,
|
kImm14Bits = 14,
|
||||||
|
kImm14Mask = 0x3fff << kImm14Shift,
|
||||||
kImm16Shift = 5,
|
kImm16Shift = 5,
|
||||||
kImm16Bits = 16,
|
kImm16Bits = 16,
|
||||||
kImm16Mask = 0xffff << kImm16Shift,
|
kImm16Mask = 0xffff << kImm16Shift,
|
||||||
|
|
Loading…
Reference in a new issue