Merge pull request #342 from JosephTremoulet/ArithmeticOverflow

Implement overflow forms of binary arithmetic
This commit is contained in:
Joseph Tremoulet 2015-03-23 19:51:00 -04:00
Родитель ffa148d6de eceeaa188c
Коммит 7caf615303
2 изменённых файлов: 56 добавлений и 29 удалений

Просмотреть файл

@ -530,10 +530,10 @@ In summary, the plan/status is:
- [ ] Implicit exceptions expanded to explicit test/throw sequences
- [x] Null dereference
- [ ] Divide by zero
- [ ] Arithmetic overflow
- [x] Arithmetic overflow
- [ ] Convert with overflow
- [ ] Array bounds checks
- [ ] Array store checks
- [x] Array bounds checks
- [x] Array store checks
2. [ ] Handler bring-up in EH branch
- [ ] Catch handler support
- [ ] In reader (includes updating throws to use `invoke` rather than

Просмотреть файл

@ -2161,47 +2161,66 @@ IRNode *GenIR::binaryOp(ReaderBaseNS::BinaryOpcode Opcode, IRNode *Arg1,
IRNode *Arg2) {
struct BinaryTriple {
Instruction::BinaryOps Opcode;
union {
Instruction::BinaryOps Opcode;
Intrinsic::ID Intrinsic;
} Op;
bool IsOverflow;
bool IsUnsigned;
// Constructor for operations that map to LLVM opcodes
BinaryTriple(Instruction::BinaryOps Opcode, bool IsOverflow,
bool IsUnsigned)
: IsOverflow(IsOverflow), IsUnsigned(IsUnsigned) {
Op.Opcode = Opcode;
}
// Constructor for operations that map to LLVM intrinsics
BinaryTriple(Intrinsic::ID Intrinsic, bool IsOverflow, bool IsUnsigned)
: IsOverflow(IsOverflow), IsUnsigned(IsUnsigned) {
Op.Intrinsic = Intrinsic;
}
// Default constructor for invalid cases
BinaryTriple() {}
};
static const BinaryTriple IntMap[ReaderBaseNS::LastBinaryOpcode] = {
{Instruction::BinaryOps::Add, false, false}, // ADD
{Instruction::BinaryOps::Add, true, false}, // ADD_OVF
{Instruction::BinaryOps::Add, true, true}, // ADD_OVF_UN
{Intrinsic::sadd_with_overflow, true, false}, // ADD_OVF
{Intrinsic::uadd_with_overflow, true, true}, // ADD_OVF_UN
{Instruction::BinaryOps::And, false, false}, // AND
{Instruction::BinaryOps::SDiv, false, false}, // DIV
{Instruction::BinaryOps::UDiv, false, true}, // DIV_UN
{Instruction::BinaryOps::Mul, false, false}, // MUL
{Instruction::BinaryOps::Mul, true, false}, // MUL_OVF
{Instruction::BinaryOps::Mul, true, true}, // MUL_OVF_UN
{Intrinsic::smul_with_overflow, true, false}, // MUL_OVF
{Intrinsic::umul_with_overflow, true, true}, // MUL_OVF_UN
{Instruction::BinaryOps::Or, false, false}, // OR
{Instruction::BinaryOps::SRem, false, false}, // REM
{Instruction::BinaryOps::URem, false, true}, // REM_UN
{Instruction::BinaryOps::Sub, false, false}, // SUB
{Instruction::BinaryOps::Sub, true, false}, // SUB_OVF
{Instruction::BinaryOps::Sub, true, true}, // SUB_OVF_UN
{Intrinsic::ssub_with_overflow, true, false}, // SUB_OVF
{Intrinsic::usub_with_overflow, true, true}, // SUB_OVF_UN
{Instruction::BinaryOps::Xor, false, false} // XOR
};
static const BinaryTriple FloatMap[ReaderBaseNS::LastBinaryOpcode] = {
{Instruction::BinaryOps::FAdd, false, false}, // ADD
{Instruction::BinaryOps::FAdd, true, false}, // ADD_OVF
{Instruction::BinaryOps::FAdd, true, true}, // ADD_OVF_UN
{Instruction::BinaryOps::And, false, false}, // AND
{}, // ADD_OVF (invalid)
{}, // ADD_OVF_UN (invalid)
{}, // AND (invalid)
{Instruction::BinaryOps::FDiv, false, false}, // DIV
{Instruction::BinaryOps::FDiv, false, true}, // DIV_UN
{}, // DIV_UN (invalid)
{Instruction::BinaryOps::FMul, false, false}, // MUL
{Instruction::BinaryOps::FMul, true, false}, // MUL_OVF
{Instruction::BinaryOps::FMul, true, true}, // MUL_OVF_UN
{Instruction::BinaryOps::Or, false, false}, // OR
{}, // MUL_OVF (invalid)
{}, // MUL_OVF_UN (invalid)
{}, // OR (invalid)
{Instruction::BinaryOps::FRem, false, false}, // REM
{Instruction::BinaryOps::FRem, false, true}, // REM_UN
{}, // REM_UN (invalid)
{Instruction::BinaryOps::FSub, false, false}, // SUB
{Instruction::BinaryOps::FSub, true, false}, // SUB_OVF
{Instruction::BinaryOps::FSub, true, true}, // SUB_OVF_UN
{Instruction::BinaryOps::Xor, false, false} // XOR
{}, // SUB_OVF (invalid)
{}, // SUB_OVF_UN (invalid)
{}, // XOR (invalid)
};
Type *Type1 = Arg1->getType();
@ -2228,15 +2247,8 @@ IRNode *GenIR::binaryOp(ReaderBaseNS::BinaryOpcode Opcode, IRNode *Arg1,
const BinaryTriple *Triple = IsFloat ? FloatMap : IntMap;
bool IsOverflow = Triple[Opcode].IsOverflow;
if (IsOverflow) {
throw NotYetImplementedException("BinaryOp Overflow");
}
bool IsUnsigned = Triple[Opcode].IsUnsigned;
Instruction::BinaryOps Op = Triple[Opcode].Opcode;
if (Type1 != ResultType) {
Arg1 = convert(ResultType, Arg1, !IsUnsigned);
}
@ -2246,7 +2258,7 @@ IRNode *GenIR::binaryOp(ReaderBaseNS::BinaryOpcode Opcode, IRNode *Arg1,
}
IRNode *Result;
if (IsFloat && Op == Instruction::BinaryOps::FRem) {
if (IsFloat && Opcode == ReaderBaseNS::BinaryOpcode::Rem) {
// FRem must be lowered to a JIT helper call to avoid undefined symbols
// during emit.
//
@ -2262,7 +2274,22 @@ IRNode *GenIR::binaryOp(ReaderBaseNS::BinaryOpcode Opcode, IRNode *Arg1,
}
Result = callHelperImpl(Helper, ResultType, Arg1, Arg2);
} else if (IsOverflow) {
// Call the appropriate intrinsic. Its result is a pair of the arithmetic
// result and a bool indicating whether the operation overflows.
Value *Intrinsic = Intrinsic::getDeclaration(
JitContext->CurrentModule, Triple[Opcode].Op.Intrinsic, ResultType);
Value *Pair = LLVMBuilder->CreateCall2(Intrinsic, Arg1, Arg2);
// Extract the bool and raise an overflow exception if set.
Value *OvfBool = LLVMBuilder->CreateExtractValue(Pair, 1, "Ovf");
genConditionalThrow(OvfBool, CORINFO_HELP_OVERFLOW, "ThrowOverflow");
// Extract the result.
Result = (IRNode *)LLVMBuilder->CreateExtractValue(Pair, 0);
} else {
// Create a simple binary operation.
Instruction::BinaryOps Op = Triple[Opcode].Op.Opcode;
Result = (IRNode *)LLVMBuilder->CreateBinOp(Op, Arg1, Arg2);
}
return Result;