S390: Fixed s390 simulation check for underflow in subtraction.
Clang optimizes away CheckOverflowForIntSub at any opt level (includes -O1, -O2, -O3) into a false statement, resulting in incorrect values being returned. As the C++ standard considers overflows to be undefined behaviour, this is technically correct as compilers can assume that overflows never occur, but problematic in our case (where overflows do occur, and a specific result is expected). This change replaces the original check with a call to a function that is optimized in a manner that returns correct output. R=michael_dawson@ca.ibm.com,jyan@ca.ibm.com,mtbrandyberry@ca.ibm.com,joransiu@ca.ibm.com,danno@chromium.org,jkummerow@chromium.org,jochen@chromium.org BUG= Review URL: https://codereview.chromium.org/1826043002 Cr-Commit-Position: refs/heads/master@{#35082}
This commit is contained in:
parent
f5b85cb74c
commit
0d24a0fcfe
@ -1150,8 +1150,9 @@ bool Simulator::BorrowFrom(int32_t left, int32_t right) {
|
||||
}
|
||||
|
||||
// Calculate V flag value for additions and subtractions.
|
||||
bool Simulator::OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
|
||||
bool addition) {
|
||||
template <typename T1>
|
||||
bool Simulator::OverflowFromSigned(T1 alu_out, T1 left, T1 right,
|
||||
bool addition) {
|
||||
bool overflow;
|
||||
if (addition) {
|
||||
// operands have the same sign
|
||||
@ -1640,12 +1641,11 @@ void Simulator::PrintStopInfo(uint32_t code) {
|
||||
// (2) Test the result and one of the operands have opposite sign
|
||||
// (a) No overflow if they don't have opposite sign
|
||||
// (b) Overflow if opposite
|
||||
#define CheckOverflowForIntAdd(src1, src2) \
|
||||
(((src1) ^ (src2)) < 0 ? false : ((((src1) + (src2)) ^ (src1)) < 0))
|
||||
#define CheckOverflowForIntAdd(src1, src2, type) \
|
||||
OverflowFromSigned<type>(src1 + src2, src1, src2, true);
|
||||
|
||||
// Method for checking overflow on signed subtraction:
|
||||
#define CheckOverflowForIntSub(src1, src2) \
|
||||
(((src1 - src2) < src1) != (src2 > 0))
|
||||
#define CheckOverflowForIntSub(src1, src2, type) \
|
||||
OverflowFromSigned<type>(src1 - src2, src1, src2, false);
|
||||
|
||||
// Method for checking overflow on unsigned addtion
|
||||
#define CheckOverflowForUIntAdd(src1, src2) \
|
||||
@ -1686,13 +1686,13 @@ bool Simulator::DecodeTwoByte(Instruction* instr) {
|
||||
bool isOF = false;
|
||||
switch (op) {
|
||||
case AR:
|
||||
isOF = CheckOverflowForIntAdd(r1_val, r2_val);
|
||||
isOF = CheckOverflowForIntAdd(r1_val, r2_val, int32_t);
|
||||
r1_val += r2_val;
|
||||
SetS390ConditionCode<int32_t>(r1_val, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
break;
|
||||
case SR:
|
||||
isOF = CheckOverflowForIntSub(r1_val, r2_val);
|
||||
isOF = CheckOverflowForIntSub(r1_val, r2_val, int32_t);
|
||||
r1_val -= r2_val;
|
||||
SetS390ConditionCode<int32_t>(r1_val, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
@ -2461,13 +2461,13 @@ bool Simulator::DecodeFourByteArithmetic(Instruction* instr) {
|
||||
bool isOF = false;
|
||||
switch (op) {
|
||||
case AGR:
|
||||
isOF = CheckOverflowForIntAdd(r1_val, r2_val);
|
||||
isOF = CheckOverflowForIntAdd(r1_val, r2_val, int64_t);
|
||||
r1_val += r2_val;
|
||||
SetS390ConditionCode<int64_t>(r1_val, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
break;
|
||||
case SGR:
|
||||
isOF = CheckOverflowForIntSub(r1_val, r2_val);
|
||||
isOF = CheckOverflowForIntSub(r1_val, r2_val, int64_t);
|
||||
r1_val -= r2_val;
|
||||
SetS390ConditionCode<int64_t>(r1_val, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
@ -2497,7 +2497,7 @@ bool Simulator::DecodeFourByteArithmetic(Instruction* instr) {
|
||||
int r2 = rreInst->R2Value();
|
||||
int64_t r1_val = get_register(r1);
|
||||
int64_t r2_val = static_cast<int64_t>(get_low_register<int32_t>(r2));
|
||||
bool isOF = CheckOverflowForIntAdd(r1_val, r2_val);
|
||||
bool isOF = CheckOverflowForIntAdd(r1_val, r2_val, int64_t);
|
||||
r1_val += r2_val;
|
||||
SetS390ConditionCode<int64_t>(r1_val, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
@ -2511,7 +2511,7 @@ bool Simulator::DecodeFourByteArithmetic(Instruction* instr) {
|
||||
int64_t r1_val = get_register(r1);
|
||||
int64_t r2_val = static_cast<int64_t>(get_low_register<int32_t>(r2));
|
||||
bool isOF = false;
|
||||
isOF = CheckOverflowForIntSub(r1_val, r2_val);
|
||||
isOF = CheckOverflowForIntSub(r1_val, r2_val, int64_t);
|
||||
r1_val -= r2_val;
|
||||
SetS390ConditionCode<int64_t>(r1_val, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
@ -2530,12 +2530,12 @@ bool Simulator::DecodeFourByteArithmetic(Instruction* instr) {
|
||||
int32_t r2_val = get_low_register<int32_t>(r2);
|
||||
int32_t r3_val = get_low_register<int32_t>(r3);
|
||||
if (ARK == op) {
|
||||
bool isOF = CheckOverflowForIntAdd(r2_val, r3_val);
|
||||
bool isOF = CheckOverflowForIntAdd(r2_val, r3_val, int32_t);
|
||||
SetS390ConditionCode<int32_t>(r2_val + r3_val, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
set_low_register(r1, r2_val + r3_val);
|
||||
} else if (SRK == op) {
|
||||
bool isOF = CheckOverflowForIntSub(r2_val, r3_val);
|
||||
bool isOF = CheckOverflowForIntSub(r2_val, r3_val, int32_t);
|
||||
SetS390ConditionCode<int32_t>(r2_val - r3_val, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
set_low_register(r1, r2_val - r3_val);
|
||||
@ -2587,12 +2587,12 @@ bool Simulator::DecodeFourByteArithmetic(Instruction* instr) {
|
||||
int64_t r2_val = get_register(r2);
|
||||
int64_t r3_val = get_register(r3);
|
||||
if (AGRK == op) {
|
||||
bool isOF = CheckOverflowForIntAdd(r2_val, r3_val);
|
||||
bool isOF = CheckOverflowForIntAdd(r2_val, r3_val, int64_t);
|
||||
SetS390ConditionCode<int64_t>(r2_val + r3_val, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
set_register(r1, r2_val + r3_val);
|
||||
} else if (SGRK == op) {
|
||||
bool isOF = CheckOverflowForIntSub(r2_val, r3_val);
|
||||
bool isOF = CheckOverflowForIntSub(r2_val, r3_val, int64_t);
|
||||
SetS390ConditionCode<int64_t>(r2_val - r3_val, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
set_register(r1, r2_val - r3_val);
|
||||
@ -2635,13 +2635,13 @@ bool Simulator::DecodeFourByteArithmetic(Instruction* instr) {
|
||||
case AHI:
|
||||
case MHI: {
|
||||
RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
||||
int r1 = riinst->R1Value();
|
||||
int i = riinst->I2Value();
|
||||
int32_t r1 = riinst->R1Value();
|
||||
int32_t i = riinst->I2Value();
|
||||
int32_t r1_val = get_low_register<int32_t>(r1);
|
||||
bool isOF = false;
|
||||
switch (op) {
|
||||
case AHI:
|
||||
isOF = CheckOverflowForIntAdd(r1_val, i);
|
||||
isOF = CheckOverflowForIntAdd(r1_val, i, int32_t);
|
||||
r1_val += i;
|
||||
break;
|
||||
case MHI:
|
||||
@ -2659,13 +2659,13 @@ bool Simulator::DecodeFourByteArithmetic(Instruction* instr) {
|
||||
case AGHI:
|
||||
case MGHI: {
|
||||
RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
||||
int r1 = riinst->R1Value();
|
||||
int32_t r1 = riinst->R1Value();
|
||||
int64_t i = static_cast<int64_t>(riinst->I2Value());
|
||||
int64_t r1_val = get_register(r1);
|
||||
bool isOF = false;
|
||||
switch (op) {
|
||||
case AGHI:
|
||||
isOF = CheckOverflowForIntAdd(r1_val, i);
|
||||
isOF = CheckOverflowForIntAdd(r1_val, i, int64_t);
|
||||
r1_val += i;
|
||||
break;
|
||||
case MGHI:
|
||||
@ -2752,13 +2752,13 @@ bool Simulator::DecodeFourByteArithmetic(Instruction* instr) {
|
||||
bool isOF = false;
|
||||
switch (op) {
|
||||
case A:
|
||||
isOF = CheckOverflowForIntAdd(r1_val, mem_val);
|
||||
isOF = CheckOverflowForIntAdd(r1_val, mem_val, int32_t);
|
||||
alu_out = r1_val + mem_val;
|
||||
SetS390ConditionCode<int32_t>(alu_out, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
break;
|
||||
case S:
|
||||
isOF = CheckOverflowForIntSub(r1_val, mem_val);
|
||||
isOF = CheckOverflowForIntSub(r1_val, mem_val, int32_t);
|
||||
alu_out = r1_val - mem_val;
|
||||
SetS390ConditionCode<int32_t>(alu_out, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
@ -2836,14 +2836,14 @@ bool Simulator::DecodeFourByteArithmetic(Instruction* instr) {
|
||||
int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
||||
intptr_t d2_val = rxinst->D2Value();
|
||||
intptr_t addr = b2_val + x2_val + d2_val;
|
||||
int16_t mem_val = ReadH(addr, instr);
|
||||
int32_t mem_val = static_cast<int32_t>(ReadH(addr, instr));
|
||||
int32_t alu_out = 0;
|
||||
bool isOF = false;
|
||||
if (AH == op) {
|
||||
isOF = CheckOverflowForIntAdd(r1_val, mem_val);
|
||||
isOF = CheckOverflowForIntAdd(r1_val, mem_val, int32_t);
|
||||
alu_out = r1_val + mem_val;
|
||||
} else if (SH == op) {
|
||||
isOF = CheckOverflowForIntSub(r1_val, mem_val);
|
||||
isOF = CheckOverflowForIntSub(r1_val, mem_val, int32_t);
|
||||
alu_out = r1_val - mem_val;
|
||||
} else if (MH == op) {
|
||||
alu_out = r1_val * mem_val;
|
||||
@ -4322,14 +4322,14 @@ bool Simulator::DecodeSixByteArithmetic(Instruction* instr) {
|
||||
// 32-bit Add
|
||||
int32_t r2_val = get_low_register<int32_t>(r2);
|
||||
int32_t imm = rieInst->I6Value();
|
||||
isOF = CheckOverflowForIntAdd(r2_val, imm);
|
||||
isOF = CheckOverflowForIntAdd(r2_val, imm, int32_t);
|
||||
set_low_register(r1, r2_val + imm);
|
||||
SetS390ConditionCode<int32_t>(r2_val + imm, 0);
|
||||
} else if (AGHIK == op) {
|
||||
// 64-bit Add
|
||||
int64_t r2_val = get_register(r2);
|
||||
int64_t imm = static_cast<int64_t>(rieInst->I6Value());
|
||||
isOF = CheckOverflowForIntAdd(r2_val, imm);
|
||||
isOF = CheckOverflowForIntAdd(r2_val, imm, int64_t);
|
||||
set_register(r1, r2_val + imm);
|
||||
SetS390ConditionCode<int64_t>(r2_val + imm, 0);
|
||||
}
|
||||
@ -4372,12 +4372,12 @@ bool Simulator::DecodeSixByteArithmetic(Instruction* instr) {
|
||||
int32_t mem_val = ReadW(b2_val + x2_val + d2, instr);
|
||||
bool isOF = false;
|
||||
if (op == AY) {
|
||||
isOF = CheckOverflowForIntAdd(alu_out, mem_val);
|
||||
isOF = CheckOverflowForIntAdd(alu_out, mem_val, int32_t);
|
||||
alu_out += mem_val;
|
||||
SetS390ConditionCode<int32_t>(alu_out, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
} else if (op == SY) {
|
||||
isOF = CheckOverflowForIntSub(alu_out, mem_val);
|
||||
isOF = CheckOverflowForIntSub(alu_out, mem_val, int32_t);
|
||||
alu_out -= mem_val;
|
||||
SetS390ConditionCode<int32_t>(alu_out, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
@ -4407,17 +4407,18 @@ bool Simulator::DecodeSixByteArithmetic(Instruction* instr) {
|
||||
int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
||||
int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
||||
intptr_t d2_val = rxyInstr->D2Value();
|
||||
int16_t mem_val = ReadH(b2_val + d2_val + x2_val, instr);
|
||||
int32_t mem_val =
|
||||
static_cast<int32_t>(ReadH(b2_val + d2_val + x2_val, instr));
|
||||
int32_t alu_out = 0;
|
||||
bool isOF = false;
|
||||
switch (op) {
|
||||
case AHY:
|
||||
alu_out = r1_val + mem_val;
|
||||
isOF = CheckOverflowForIntAdd(r1_val, mem_val);
|
||||
isOF = CheckOverflowForIntAdd(r1_val, mem_val, int32_t);
|
||||
break;
|
||||
case SHY:
|
||||
alu_out = r1_val - mem_val;
|
||||
isOF = CheckOverflowForIntSub(r1_val, mem_val);
|
||||
isOF = CheckOverflowForIntSub(r1_val, mem_val, int64_t);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -4520,20 +4521,21 @@ bool Simulator::DecodeSixByteArithmetic(Instruction* instr) {
|
||||
case AFI: {
|
||||
// Clobbering Add Word Immediate
|
||||
RILInstruction* rilInstr = reinterpret_cast<RILInstruction*>(instr);
|
||||
int r1 = rilInstr->R1Value();
|
||||
int i2 = rilInstr->I2Value();
|
||||
int32_t r1 = rilInstr->R1Value();
|
||||
bool isOF = false;
|
||||
if (AFI == op) {
|
||||
// 32-bit Add (Register + 32-bit Immediate)
|
||||
int32_t r1_val = get_low_register<int32_t>(r1);
|
||||
isOF = CheckOverflowForIntAdd(r1_val, i2);
|
||||
int32_t i2 = rilInstr->I2Value();
|
||||
isOF = CheckOverflowForIntAdd(r1_val, i2, int32_t);
|
||||
int32_t alu_out = r1_val + i2;
|
||||
set_low_register(r1, alu_out);
|
||||
SetS390ConditionCode<int32_t>(alu_out, 0);
|
||||
} else if (AGFI == op) {
|
||||
// 64-bit Add (Register + 32-bit Imm)
|
||||
int64_t r1_val = get_register(r1);
|
||||
isOF = CheckOverflowForIntAdd(r1_val, i2);
|
||||
int64_t i2 = static_cast<int64_t>(rilInstr->I2Value());
|
||||
isOF = CheckOverflowForIntAdd(r1_val, i2, int64_t);
|
||||
int64_t alu_out = r1_val + i2;
|
||||
set_register(r1, alu_out);
|
||||
SetS390ConditionCode<int64_t>(alu_out, 0);
|
||||
@ -4542,7 +4544,12 @@ bool Simulator::DecodeSixByteArithmetic(Instruction* instr) {
|
||||
break;
|
||||
}
|
||||
case ASI: {
|
||||
int8_t i2 = static_cast<int8_t>(siyInstr->I2Value());
|
||||
// TODO(bcleung): Change all fooInstr->I2Value() to template functions.
|
||||
// The below static cast to 8 bit and then to 32 bit is necessary
|
||||
// because siyInstr->I2Value() returns a uint8_t, which a direct
|
||||
// cast to int32_t could incorrectly interpret.
|
||||
int8_t i2_8bit = static_cast<int8_t>(siyInstr->I2Value());
|
||||
int32_t i2 = static_cast<int32_t>(i2_8bit);
|
||||
int b1 = siyInstr->B1Value();
|
||||
intptr_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
||||
|
||||
@ -4550,7 +4557,7 @@ bool Simulator::DecodeSixByteArithmetic(Instruction* instr) {
|
||||
intptr_t addr = b1_val + d1_val;
|
||||
|
||||
int32_t mem_val = ReadW(addr, instr);
|
||||
bool isOF = CheckOverflowForIntAdd(mem_val, i2);
|
||||
bool isOF = CheckOverflowForIntAdd(mem_val, i2, int32_t);
|
||||
int32_t alu_out = mem_val + i2;
|
||||
SetS390ConditionCode<int32_t>(alu_out, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
@ -4558,7 +4565,12 @@ bool Simulator::DecodeSixByteArithmetic(Instruction* instr) {
|
||||
break;
|
||||
}
|
||||
case AGSI: {
|
||||
int8_t i2 = static_cast<int8_t>(siyInstr->I2Value());
|
||||
// TODO(bcleung): Change all fooInstr->I2Value() to template functions.
|
||||
// The below static cast to 8 bit and then to 32 bit is necessary
|
||||
// because siyInstr->I2Value() returns a uint8_t, which a direct
|
||||
// cast to int32_t could incorrectly interpret.
|
||||
int8_t i2_8bit = static_cast<int8_t>(siyInstr->I2Value());
|
||||
int64_t i2 = static_cast<int64_t>(i2_8bit);
|
||||
int b1 = siyInstr->B1Value();
|
||||
intptr_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
||||
|
||||
@ -4566,7 +4578,7 @@ bool Simulator::DecodeSixByteArithmetic(Instruction* instr) {
|
||||
intptr_t addr = b1_val + d1_val;
|
||||
|
||||
int64_t mem_val = ReadDW(addr);
|
||||
int isOF = CheckOverflowForIntAdd(mem_val, i2);
|
||||
int isOF = CheckOverflowForIntAdd(mem_val, i2, int64_t);
|
||||
int64_t alu_out = mem_val + i2;
|
||||
SetS390ConditionCode<uint64_t>(alu_out, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
|
@ -258,8 +258,8 @@ class Simulator {
|
||||
// Helper functions to set the conditional flags in the architecture state.
|
||||
bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
|
||||
bool BorrowFrom(int32_t left, int32_t right);
|
||||
bool OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
|
||||
bool addition);
|
||||
template <typename T1>
|
||||
inline bool OverflowFromSigned(T1 alu_out, T1 left, T1 right, bool addition);
|
||||
|
||||
// Helper functions to decode common "addressing" modes
|
||||
int32_t GetShiftRm(Instruction* instr, bool* carry_out);
|
||||
|
Loading…
Reference in New Issue
Block a user