Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2587)

Unified Diff: runtime/vm/simulator_arm64.cc

Issue 630093004: Fix 32-bit and 64-bit carry out calculation in arm64 simulator. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/simulator_arm64.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/simulator_arm64.cc
===================================================================
--- runtime/vm/simulator_arm64.cc (revision 40988)
+++ runtime/vm/simulator_arm64.cc (working copy)
@@ -939,44 +939,22 @@
}
-// Calculate C flag value for additions.
-bool Simulator::CarryFromW(int32_t left, int32_t right) {
- uint32_t uleft = static_cast<uint32_t>(left);
- uint32_t uright = static_cast<uint32_t>(right);
- uint32_t urest = 0xffffffffU - uleft;
-
- return (uright > urest);
+// Calculate C flag value for additions (and subtractions with adjusted args).
+bool Simulator::CarryFromW(int32_t left, int32_t right, int32_t carry) {
+ uint64_t uleft = static_cast<uint32_t>(left);
+ uint64_t uright = static_cast<uint32_t>(right);
+ uint64_t ucarry = static_cast<uint32_t>(carry);
+ return ((uleft + uright + ucarry) >> 32) != 0;
}
-// Calculate C flag value for subtractions.
-bool Simulator::BorrowFromW(int32_t left, int32_t right) {
- uint32_t uleft = static_cast<uint32_t>(left);
- uint32_t uright = static_cast<uint32_t>(right);
-
- return (uright > uleft);
+// Calculate V flag value for additions (and subtractions with adjusted args).
+bool Simulator::OverflowFromW(int32_t left, int32_t right, int32_t carry) {
+ int64_t result = static_cast<int64_t>(left) + right + carry;
+ return (result >> 31) != (result >> 32);
}
-// Calculate V flag value for additions and subtractions.
-bool Simulator::OverflowFromW(int32_t alu_out,
- int32_t left, int32_t right, bool addition) {
- bool overflow;
- if (addition) {
- // operands have the same sign
- overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
- // and operands and result have different sign
- && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
- } else {
- // operands have different signs
- overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
- // and first operand and result have different signs
- && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
- }
- return overflow;
-}
-
-
// Calculate and set the Negative and Zero flags.
void Simulator::SetNZFlagsX(int64_t val) {
n_flag_ = (val < 0);
@@ -984,41 +962,25 @@
}
-// Calculate C flag value for additions.
-bool Simulator::CarryFromX(int64_t left, int64_t right) {
- uint64_t uleft = static_cast<uint64_t>(left);
- uint64_t uright = static_cast<uint64_t>(right);
- uint64_t urest = 0xffffffffffffffffULL - uleft;
-
- return (uright > urest);
+// Calculate C flag value for additions and subtractions.
+bool Simulator::CarryFromX(int64_t alu_out,
+ int64_t left, int64_t right, bool addition) {
+ if (addition) {
+ return (((left & right) | ((left | right) & ~alu_out)) >> 63) != 0;
+ } else {
+ return (((~left & right) | ((~left | right) & alu_out)) >> 63) == 0;
+ }
}
-// Calculate C flag value for subtractions.
-bool Simulator::BorrowFromX(int64_t left, int64_t right) {
- uint64_t uleft = static_cast<uint64_t>(left);
- uint64_t uright = static_cast<uint64_t>(right);
-
- return (uright > uleft);
-}
-
-
// Calculate V flag value for additions and subtractions.
bool Simulator::OverflowFromX(int64_t alu_out,
int64_t left, int64_t right, bool addition) {
- bool overflow;
if (addition) {
- // operands have the same sign
- overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
- // and operands and result have different sign
- && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
+ return (((alu_out ^ left) & (alu_out ^ right)) >> 63) != 0;
} else {
- // operands have different signs
- overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
- // and first operand and result have different signs
- && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
+ return (((left ^ right) & (alu_out ^ left)) >> 63) != 0;
}
- return overflow;
}
@@ -1079,13 +1041,13 @@
void Simulator::DecodeAddSubImm(Instr* instr) {
- bool addition = (instr->Bit(30) == 0);
+ const bool addition = (instr->Bit(30) == 0);
// Format(instr, "addi'sf's 'rd, 'rn, 'imm12s");
// Format(instr, "subi'sf's 'rd, 'rn, 'imm12s");
const Register rd = instr->RdField();
const Register rn = instr->RnField();
- const uint32_t imm = (instr->Bit(22) == 1) ? (instr->Imm12Field() << 12)
- : (instr->Imm12Field());
+ uint32_t imm = (instr->Bit(22) == 1) ? (instr->Imm12Field() << 12)
+ : (instr->Imm12Field());
if (instr->SFField()) {
// 64-bit add.
const int64_t rn_val = get_register(rn, instr->RnMode());
@@ -1093,26 +1055,23 @@
set_register(instr, rd, alu_out, instr->RdMode());
if (instr->HasS()) {
SetNZFlagsX(alu_out);
- if (addition) {
- SetCFlag(CarryFromX(rn_val, imm));
- } else {
- SetCFlag(!BorrowFromX(rn_val, imm));
- }
+ SetCFlag(CarryFromX(alu_out, rn_val, imm, addition));
SetVFlag(OverflowFromX(alu_out, rn_val, imm, addition));
}
} else {
// 32-bit add.
const int32_t rn_val = get_wregister(rn, instr->RnMode());
- const int32_t alu_out = addition ? (rn_val + imm) : (rn_val - imm);
+ int32_t carry_in = 0;
+ if (!addition) {
+ carry_in = 1;
+ imm = ~imm;
+ }
+ const int32_t alu_out = rn_val + imm + carry_in;
set_wregister(rd, alu_out, instr->RdMode());
if (instr->HasS()) {
SetNZFlagsW(alu_out);
- if (addition) {
- SetCFlag(CarryFromW(rn_val, imm));
- } else {
- SetCFlag(!BorrowFromW(rn_val, imm));
- }
- SetVFlag(OverflowFromW(alu_out, rn_val, imm, addition));
+ SetCFlag(CarryFromW(rn_val, imm, carry_in));
+ SetVFlag(OverflowFromW(rn_val, imm, carry_in));
}
}
}
@@ -1943,7 +1902,7 @@
void Simulator::DecodeAddSubShiftExt(Instr* instr) {
// Format(instr, "add'sf's 'rd, 'rn, 'shift_op");
// also, sub, cmp, etc.
- const bool subtract = instr->Bit(30) == 1;
+ const bool addition = (instr->Bit(30) == 0);
const Register rd = instr->RdField();
const Register rn = instr->RnField();
const int64_t rm_val = DecodeShiftExtendOperand(instr);
@@ -1950,46 +1909,71 @@
if (instr->SFField()) {
// 64-bit add.
const int64_t rn_val = get_register(rn, instr->RnMode());
- int64_t alu_out = 0;
- if (subtract) {
- alu_out = rn_val - rm_val;
- } else {
- alu_out = rn_val + rm_val;
- }
+ const int64_t alu_out = rn_val + (addition ? rm_val : -rm_val);
set_register(instr, rd, alu_out, instr->RdMode());
if (instr->HasS()) {
SetNZFlagsX(alu_out);
- if (subtract) {
- SetCFlag(!BorrowFromX(rn_val, rm_val));
- } else {
- SetCFlag(CarryFromX(rn_val, rm_val));
- }
- SetVFlag(OverflowFromX(alu_out, rn_val, rm_val, !subtract));
+ SetCFlag(CarryFromX(alu_out, rn_val, rm_val, addition));
+ SetVFlag(OverflowFromX(alu_out, rn_val, rm_val, addition));
}
} else {
// 32-bit add.
const int32_t rn_val = get_wregister(rn, instr->RnMode());
- const int32_t rm_val32 = static_cast<int32_t>(rm_val & kWRegMask);
- int32_t alu_out = 0;
- if (subtract) {
- alu_out = rn_val - rm_val32;
- } else {
- alu_out = rn_val + rm_val32;
+ int32_t rm_val32 = static_cast<int32_t>(rm_val & kWRegMask);
+ int32_t carry_in = 0;
+ if (!addition) {
+ carry_in = 1;
+ rm_val32 = ~rm_val32;
}
+ const int32_t alu_out = rn_val + rm_val32 + carry_in;
set_wregister(rd, alu_out, instr->RdMode());
if (instr->HasS()) {
SetNZFlagsW(alu_out);
- if (subtract) {
- SetCFlag(!BorrowFromW(rn_val, rm_val32));
- } else {
- SetCFlag(CarryFromW(rn_val, rm_val32));
- }
- SetVFlag(OverflowFromW(alu_out, rn_val, rm_val32, !subtract));
+ SetCFlag(CarryFromW(rn_val, rm_val32, carry_in));
+ SetVFlag(OverflowFromW(rn_val, rm_val32, carry_in));
}
}
}
+void Simulator::DecodeAddSubWithCarry(Instr* instr) {
+ // Format(instr, "adc'sf's 'rd, 'rn, 'rm");
+ // Format(instr, "sbc'sf's 'rd, 'rn, 'rm");
+ const bool addition = (instr->Bit(30) == 0);
+ const Register rd = instr->RdField();
+ const Register rn = instr->RnField();
+ const Register rm = instr->RmField();
+ const int64_t rn_val64 = get_register(rn, R31IsZR);
+ const int32_t rn_val32 = get_wregister(rn, R31IsZR);
+ const int64_t rm_val64 = get_register(rm, R31IsZR);
+ int32_t rm_val32 = get_wregister(rm, R31IsZR);
+ const int32_t carry_in = c_flag_ ? 1 : 0;
+ if (instr->SFField()) {
+ // 64-bit add.
+ const int64_t alu_out =
+ rn_val64 + (addition ? rm_val64 : ~rm_val64) + carry_in;
+ set_register(instr, rd, alu_out, R31IsZR);
+ if (instr->HasS()) {
+ SetNZFlagsX(alu_out);
+ SetCFlag(CarryFromX(alu_out, rn_val64, rm_val64, addition));
+ SetVFlag(OverflowFromX(alu_out, rn_val64, rm_val64, addition));
+ }
+ } else {
+ // 32-bit add.
+ if (!addition) {
+ rm_val32 = ~rm_val32;
+ }
+ const int32_t alu_out = rn_val32 + rm_val32 + carry_in;
+ set_wregister(rd, alu_out, R31IsZR);
+ if (instr->HasS()) {
+ SetNZFlagsW(alu_out);
+ SetCFlag(CarryFromW(rn_val32, rm_val32, carry_in));
+ SetVFlag(OverflowFromW(rn_val32, rm_val32, carry_in));
+ }
+ }
+}
+
+
void Simulator::DecodeLogicalShift(Instr* instr) {
const int op = (instr->Bits(29, 2) << 1) | instr->Bit(21);
const Register rd = instr->RdField();
@@ -2271,6 +2255,8 @@
void Simulator::DecodeDPRegister(Instr* instr) {
if (instr->IsAddSubShiftExtOp()) {
DecodeAddSubShiftExt(instr);
+ } else if (instr->IsAddSubWithCarryOp()) {
+ DecodeAddSubWithCarry(instr);
} else if (instr->IsLogicalShiftOp()) {
DecodeLogicalShift(instr);
} else if (instr->IsMiscDP2SourceOp()) {
« no previous file with comments | « runtime/vm/simulator_arm64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698