mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 03:28:20 +02:00
Arithmetic overflow checks
This commit is contained in:
parent
1f0d2dcc82
commit
eb375362a1
29 changed files with 503 additions and 87 deletions
|
@ -102,6 +102,8 @@ namespace IDE
|
|||
[Reflect]
|
||||
public bool? mEmitObjectAccessCheck; // Only valid with mObjectHasDebugFlags
|
||||
[Reflect]
|
||||
public bool? mArithmeticCheck;
|
||||
[Reflect]
|
||||
public int32? mAllocStackTraceDepth;
|
||||
[Reflect]
|
||||
public BuildOptions.AlwaysIncludeKind mReflectAlwaysInclude;
|
||||
|
@ -135,6 +137,7 @@ namespace IDE
|
|||
newVal.mInitLocalVariables = mInitLocalVariables;
|
||||
newVal.mEmitDynamicCastCheck = mEmitDynamicCastCheck;
|
||||
newVal.mEmitObjectAccessCheck = mEmitObjectAccessCheck;
|
||||
newVal.mArithmeticCheck = mArithmeticCheck;
|
||||
newVal.mAllocStackTraceDepth = mAllocStackTraceDepth;
|
||||
newVal.mReflectAlwaysInclude = mReflectAlwaysInclude;
|
||||
newVal.mReflectBoxing = mReflectBoxing;
|
||||
|
@ -164,6 +167,8 @@ namespace IDE
|
|||
mEmitDynamicCastCheck = data.GetBool("EmitDynamicCastCheck");
|
||||
if (data.Contains("EmitObjectAccessCheck"))
|
||||
mEmitObjectAccessCheck = data.GetBool("EmitObjectAccessCheck");
|
||||
if (data.Contains("ArithmeticCheck"))
|
||||
mArithmeticCheck = data.GetBool("ArithmeticCheck");
|
||||
if (data.Contains("AllocStackTraceDepth"))
|
||||
mAllocStackTraceDepth = data.GetInt("AllocStackTraceDepth");
|
||||
|
||||
|
@ -194,6 +199,7 @@ namespace IDE
|
|||
data.ConditionalAdd("InitLocalVariables", mInitLocalVariables);
|
||||
data.ConditionalAdd("EmitDynamicCastCheck", mEmitDynamicCastCheck);
|
||||
data.ConditionalAdd("EmitObjectAccessCheck", mEmitObjectAccessCheck);
|
||||
data.ConditionalAdd("ArithmeticCheck", mArithmeticCheck);
|
||||
data.ConditionalAdd("AllocStackTraceDepth", mAllocStackTraceDepth);
|
||||
data.ConditionalAdd("ReflectAlwaysInclude", mReflectAlwaysInclude);
|
||||
data.ConditionalAdd("ReflectBoxing", mReflectBoxing);
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace IDE.Compiler
|
|||
DebugAlloc = 0x8000,
|
||||
OmitDebugHelpers = 0x10000,
|
||||
NoFramePointerElim = 0x20000,
|
||||
ArithmeticChecks = 0x40000
|
||||
}
|
||||
|
||||
[CallingConvention(.Stdcall), CLink]
|
||||
|
@ -663,6 +664,7 @@ namespace IDE.Compiler
|
|||
SetOpt(options.mEmitDynamicCastCheck, .EmitDynamicCastCheck);
|
||||
SetOpt(enableObjectDebugFlags, .EnableObjectDebugFlags);
|
||||
SetOpt(emitObjectAccessCheck, .EmitObjectAccessCheck);
|
||||
SetOpt(options.mArithmeticCheck, .ArithmeticChecks);
|
||||
|
||||
if (options.LeakCheckingEnabled)
|
||||
SetOpt(options.mEnableRealtimeLeakCheck, .EnableRealtimeLeakCheck);
|
||||
|
|
|
@ -15,18 +15,19 @@ namespace IDE.Compiler
|
|||
InitLocalVariables = 2,
|
||||
EmitDynamicCastCheck = 4,
|
||||
EmitObjectAccessCheck = 8,
|
||||
ArithmeticCheck = 0x10,
|
||||
|
||||
ReflectAlwaysIncludeType = 0x10,
|
||||
ReflectAlwaysIncludeAll = 0x20,
|
||||
ReflectAssumeInstantiated = 0x40,
|
||||
ReflectBoxing = 0x80,
|
||||
ReflectStaticFields = 0x100,
|
||||
ReflectNonStaticFields = 0x200,
|
||||
ReflectStaticMethods = 0x400,
|
||||
ReflectNonStaticMethods = 0x800,
|
||||
ReflectConstructors = 0x1000,
|
||||
ReflectAlwaysIncludeType = 0x20,
|
||||
ReflectAlwaysIncludeAll = 0x40,
|
||||
ReflectAssumeInstantiated = 0x80,
|
||||
ReflectBoxing = 0x100,
|
||||
ReflectStaticFields = 0x200,
|
||||
ReflectNonStaticFields = 0x400,
|
||||
ReflectStaticMethods = 0x800,
|
||||
ReflectNonStaticMethods = 0x1000,
|
||||
ReflectConstructors = 0x2000,
|
||||
|
||||
All = 0x1FFF
|
||||
All = 0x3FFF
|
||||
};
|
||||
|
||||
[CallingConvention(.Stdcall), CLink]
|
||||
|
@ -408,6 +409,8 @@ namespace IDE.Compiler
|
|||
SetFlag(typeOption.mReflectStaticMethods, .ReflectStaticMethods);
|
||||
SetFlag(typeOption.mReflectNonStaticMethods, .ReflectNonStaticMethods);
|
||||
SetFlag(typeOption.mReflectConstructors, .ReflectConstructors);
|
||||
SetFlag(typeOption.mEmitObjectAccessCheck, .EmitObjectAccessCheck);
|
||||
SetFlag(typeOption.mArithmeticCheck, .ArithmeticCheck);
|
||||
|
||||
AddTypeOptions(typeOption.mFilter, typeOption.mBfSIMDSetting, typeOption.mBfOptimizationLevel, typeOption.mEmitDebugInfo, andFlags, orFlags, typeOption.mAllocStackTraceDepth, typeOption.mReflectMethodFilter);
|
||||
}
|
||||
|
|
|
@ -240,6 +240,8 @@ namespace IDE
|
|||
[Reflect]
|
||||
public bool mEmitObjectAccessCheck; // Only valid with mObjectHasDebugFlags
|
||||
[Reflect]
|
||||
public bool mArithmeticCheck;
|
||||
[Reflect]
|
||||
public bool mEnableRealtimeLeakCheck;
|
||||
[Reflect]
|
||||
public bool mEnableSideStack;
|
||||
|
@ -297,6 +299,7 @@ namespace IDE
|
|||
mEmitDynamicCastCheck = prev.mEmitDynamicCastCheck;
|
||||
mEnableObjectDebugFlags = prev.mEnableObjectDebugFlags;
|
||||
mEmitObjectAccessCheck = prev.mEmitObjectAccessCheck;
|
||||
mArithmeticCheck = prev.mArithmeticCheck;
|
||||
mEnableRealtimeLeakCheck = prev.mEnableRealtimeLeakCheck;
|
||||
mEnableSideStack = prev.mEnableSideStack;
|
||||
mAllowHotSwapping = prev.mAllowHotSwapping;
|
||||
|
@ -694,6 +697,7 @@ namespace IDE
|
|||
data.ConditionalAdd("EmitDynamicCastCheck", options.mEmitDynamicCastCheck, !isRelease);
|
||||
data.ConditionalAdd("EnableObjectDebugFlags", options.mEnableObjectDebugFlags, !isRelease);
|
||||
data.ConditionalAdd("EmitObjectAccessCheck", options.mEmitObjectAccessCheck, !isRelease);
|
||||
data.ConditionalAdd("ArithmeticCheck", options.mArithmeticCheck, false);
|
||||
data.ConditionalAdd("EnableRealtimeLeakCheck", options.mEnableRealtimeLeakCheck, (platformType == .Windows) && !isRelease);
|
||||
data.ConditionalAdd("EnableSideStack", options.mEnableSideStack, (platformType == .Windows) && isParanoid);
|
||||
data.ConditionalAdd("AllowHotSwapping", options.mAllowHotSwapping, (platformType == .Windows) && !isRelease);
|
||||
|
@ -888,6 +892,7 @@ namespace IDE
|
|||
options.mEmitDynamicCastCheck = !isRelease;
|
||||
options.mEnableObjectDebugFlags = !isRelease;
|
||||
options.mEmitObjectAccessCheck = !isRelease;
|
||||
options.mArithmeticCheck = false;
|
||||
|
||||
if (platformType == .Windows)
|
||||
{
|
||||
|
@ -994,6 +999,7 @@ namespace IDE
|
|||
options.mEmitDynamicCastCheck = data.GetBool("EmitDynamicCastCheck", !isRelease);
|
||||
options.mEnableObjectDebugFlags = data.GetBool("EnableObjectDebugFlags", !isRelease);
|
||||
options.mEmitObjectAccessCheck = data.GetBool("EmitObjectAccessCheck", !isRelease);
|
||||
options.mArithmeticCheck = data.GetBool("ArithmeticCheck", false);
|
||||
options.mEnableRealtimeLeakCheck = data.GetBool("EnableRealtimeLeakCheck", (platformType == .Windows) && !isRelease);
|
||||
options.mEnableSideStack = data.GetBool("EnableSideStack", (platformType == .Windows) && isParanoid);
|
||||
options.mAllowHotSwapping = data.GetBool("AllowHotSwapping", (platformType == .Windows) && !isRelease);
|
||||
|
|
|
@ -143,6 +143,10 @@ namespace IDE.ui
|
|||
AddPropertiesItem(category, "Object Access Check", typeName,
|
||||
scope String[] ( "No", "Yes" ));
|
||||
|
||||
typeName.Clear(); typeName.Append(optionsName, "mArithmeticCheck");
|
||||
AddPropertiesItem(category, "Arithmetic Check", typeName,
|
||||
scope String[] ( "No", "Yes" ));
|
||||
|
||||
typeName.Clear(); typeName.Append(optionsName, "mAllocStackTraceDepth");
|
||||
AddPropertiesItem(category, "Alloc Stack Trace Depth", typeName);
|
||||
|
||||
|
|
|
@ -796,6 +796,8 @@ namespace IDE.ui
|
|||
scope String[] ( "No", "Yes" ));
|
||||
AddPropertiesItem(category, "Object Access Check", "mEmitObjectAccessCheck",
|
||||
scope String[] ( "No", "Yes" ));
|
||||
AddPropertiesItem(category, "Arithmetic Check", "mArithmeticCheck",
|
||||
scope String[] ( "No", "Yes" ));
|
||||
AddPropertiesItem(category, "Realtime Leak Check", "mEnableRealtimeLeakCheck",
|
||||
scope String[] ( "No", "Yes" ));
|
||||
AddPropertiesItem(category, "Enable Hot Compilation", "mAllowHotSwapping",
|
||||
|
|
|
@ -590,6 +590,11 @@ void BeIRCodeGen::Read(bool& val)
|
|||
BE_MEM_END("bool");
|
||||
}
|
||||
|
||||
void BeIRCodeGen::Read(int8& val)
|
||||
{
|
||||
val = mStream->Read();
|
||||
}
|
||||
|
||||
void BeIRCodeGen::Read(BeIRTypeEntry*& type)
|
||||
{
|
||||
BE_MEM_START;
|
||||
|
@ -1432,21 +1437,24 @@ void BeIRCodeGen::HandleNextCmd()
|
|||
{
|
||||
CMD_PARAM(BeValue*, lhs);
|
||||
CMD_PARAM(BeValue*, rhs);
|
||||
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Add, lhs, rhs));
|
||||
CMD_PARAM(int8, overflowCheckKind);
|
||||
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Add, lhs, rhs, (BfOverflowCheckKind)overflowCheckKind));
|
||||
}
|
||||
break;
|
||||
case BfIRCmd_Sub:
|
||||
{
|
||||
CMD_PARAM(BeValue*, lhs);
|
||||
CMD_PARAM(BeValue*, rhs);
|
||||
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Subtract, lhs, rhs));
|
||||
CMD_PARAM(int8, overflowCheckKind);
|
||||
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Subtract, lhs, rhs, (BfOverflowCheckKind)overflowCheckKind));
|
||||
}
|
||||
break;
|
||||
case BfIRCmd_Mul:
|
||||
{
|
||||
CMD_PARAM(BeValue*, lhs);
|
||||
CMD_PARAM(BeValue*, rhs);
|
||||
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Multiply, lhs, rhs));
|
||||
CMD_PARAM(int8, overflowCheckKind);
|
||||
SetResult(curId, mBeModule->CreateBinaryOp(BeBinaryOpKind_Multiply, lhs, rhs, (BfOverflowCheckKind)overflowCheckKind));
|
||||
}
|
||||
break;
|
||||
case BfIRCmd_SDiv:
|
||||
|
@ -2100,6 +2108,11 @@ void BeIRCodeGen::HandleNextCmd()
|
|||
mBeModule->RemoveBlock(mActiveFunction, fromBlock);
|
||||
}
|
||||
break;
|
||||
case BfIRCmd_GetInsertBlock:
|
||||
{
|
||||
SetResult(curId, mBeModule->mActiveBlock);
|
||||
}
|
||||
break;
|
||||
case BfIRCmd_SetInsertPoint:
|
||||
{
|
||||
CMD_PARAM(BeBlock*, block);
|
||||
|
|
|
@ -119,6 +119,7 @@ public:
|
|||
void Read(int64& i);
|
||||
void Read(Val128& i);
|
||||
void Read(bool& val);
|
||||
void Read(int8& val);
|
||||
void Read(BeIRTypeEntry*& type);
|
||||
void Read(BeType*& beType);
|
||||
void Read(BeFunctionType*& beType);
|
||||
|
|
|
@ -6123,6 +6123,10 @@ uint8 BeMCContext::GetJumpOpCode(BeCmpKind cmpKind, bool isLong)
|
|||
return 0x8D;
|
||||
case BeCmpKind_UGE: // JAE
|
||||
return 0x83;
|
||||
case BeCmpKind_NB: // JNB
|
||||
return 0x83;
|
||||
case BeCmpKind_NO: // JNO
|
||||
return 0x81;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -6151,6 +6155,10 @@ uint8 BeMCContext::GetJumpOpCode(BeCmpKind cmpKind, bool isLong)
|
|||
return 0x7D;
|
||||
case BeCmpKind_UGE: // JAE
|
||||
return 0x73;
|
||||
case BeCmpKind_NB: // JNB
|
||||
return 0x73;
|
||||
case BeCmpKind_NO: // JNO
|
||||
return 0x71;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10116,8 +10124,10 @@ bool BeMCContext::DoLegalization()
|
|||
break;
|
||||
case BeMCInstKind_Mul:
|
||||
case BeMCInstKind_IMul:
|
||||
{
|
||||
if (arg0Type->mSize == 1)
|
||||
{
|
||||
bool handled = false;
|
||||
|
||||
if ((arg0Type->mSize == 1) && (arg0Type->IsIntable()))
|
||||
{
|
||||
if ((!arg0.IsNativeReg()) || (arg0.mReg != X64Reg_AL) || (inst->mResult))
|
||||
{
|
||||
|
@ -10152,8 +10162,54 @@ bool BeMCContext::DoLegalization()
|
|||
}
|
||||
|
||||
BF_ASSERT(!inst->mResult);
|
||||
handled = true;
|
||||
}
|
||||
else
|
||||
else if ((inst->mKind == BeMCInstKind_Mul) && (arg0Type->IsIntable()))
|
||||
{
|
||||
auto wantReg0 = ResizeRegister(X64Reg_RAX, arg0Type->mSize);
|
||||
|
||||
if ((!arg0.IsNativeReg()) || (arg0.mReg != wantReg0) || (inst->mResult))
|
||||
{
|
||||
auto srcVRegInfo = GetVRegInfo(inst->mArg0);
|
||||
// unsigned multiplies can only be done on AX/EAX/RAX
|
||||
AllocInst(BeMCInstKind_PreserveVolatiles, BeMCOperand::FromReg(X64Reg_RAX), instIdx++);
|
||||
AllocInst(BeMCInstKind_PreserveVolatiles, BeMCOperand::FromReg(X64Reg_RDX), instIdx++);
|
||||
|
||||
auto vregInfo0 = GetVRegInfo(inst->mArg0);
|
||||
if (vregInfo0 != NULL)
|
||||
{
|
||||
vregInfo0->mDisableRAX = true;
|
||||
vregInfo0->mDisableRDX = true;
|
||||
}
|
||||
|
||||
auto vregInfo1 = GetVRegInfo(inst->mArg1);
|
||||
if (vregInfo1 != NULL)
|
||||
{
|
||||
vregInfo1->mDisableRAX = true;
|
||||
vregInfo1->mDisableRDX = true;
|
||||
}
|
||||
|
||||
AllocInst(BeMCInstKind_Mov, BeMCOperand::FromReg(wantReg0), inst->mArg0, instIdx++);
|
||||
AllocInst(BeMCInstKind_Mov, inst->mResult ? inst->mResult : inst->mArg0, BeMCOperand::FromReg(wantReg0), instIdx++ + 1);
|
||||
inst->mArg0 = BeMCOperand::FromReg(wantReg0);
|
||||
inst->mResult = BeMCOperand();
|
||||
AllocInst(BeMCInstKind_RestoreVolatiles, BeMCOperand::FromReg(X64Reg_RDX), instIdx++ + 1);
|
||||
AllocInst(BeMCInstKind_RestoreVolatiles, BeMCOperand::FromReg(X64Reg_RAX), instIdx++ + 1);
|
||||
|
||||
isFinalRun = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst->mArg1.IsImmediateInt())
|
||||
{
|
||||
ReplaceWithNewVReg(inst->mArg1, instIdx, true, false);
|
||||
}
|
||||
|
||||
BF_ASSERT(!inst->mResult);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (handled)
|
||||
{
|
||||
if (inst->mResult)
|
||||
{
|
||||
|
@ -14404,6 +14460,51 @@ void BeMCContext::DoCodeEmission()
|
|||
}
|
||||
break;
|
||||
case BeMCInstKind_Mul:
|
||||
{
|
||||
if (arg0Type->IsIntable())
|
||||
{
|
||||
bool isValid = true;
|
||||
auto typeCode = GetType(inst->mArg1)->mTypeCode;
|
||||
switch (typeCode)
|
||||
{
|
||||
case BeTypeCode_Int8:
|
||||
isValid = inst->mArg0 == BeMCOperand::FromReg(X64Reg_AL);
|
||||
break;
|
||||
case BeTypeCode_Int16:
|
||||
isValid = inst->mArg0 == BeMCOperand::FromReg(X64Reg_AX);
|
||||
break;
|
||||
case BeTypeCode_Int32:
|
||||
isValid = inst->mArg0 == BeMCOperand::FromReg(X64Reg_EAX);
|
||||
break;
|
||||
case BeTypeCode_Int64:
|
||||
isValid = inst->mArg0 == BeMCOperand::FromReg(X64Reg_RAX);
|
||||
break;
|
||||
default:
|
||||
isValid = false;
|
||||
}
|
||||
if (!isValid)
|
||||
SoftFail("Invalid mul arguments");
|
||||
|
||||
switch (typeCode)
|
||||
{
|
||||
case BeTypeCode_Int8:
|
||||
EmitREX(BeMCOperand(), inst->mArg1, false);
|
||||
Emit(0xF6);
|
||||
EmitModRM(4, inst->mArg1);
|
||||
break;
|
||||
case BeTypeCode_Int16: Emit(0x66); // Fallthrough
|
||||
case BeTypeCode_Int32:
|
||||
case BeTypeCode_Int64:
|
||||
EmitREX(BeMCOperand(), inst->mArg1, typeCode == BeTypeCode_Int64);
|
||||
Emit(0xF7); EmitModRM(4, inst->mArg1);
|
||||
break;
|
||||
default:
|
||||
NotImpl();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Fallthrough
|
||||
case BeMCInstKind_IMul:
|
||||
{
|
||||
if (instForm == BeMCInstForm_XMM128_RM128)
|
||||
|
@ -14932,17 +15033,25 @@ void BeMCContext::DoCodeEmission()
|
|||
break;
|
||||
case BeMCInstKind_CondBr:
|
||||
{
|
||||
BF_ASSERT(inst->mArg0.mKind == BeMCOperandKind_Label);
|
||||
BeMCJump jump;
|
||||
jump.mCodeOffset = funcCodePos;
|
||||
jump.mLabelIdx = inst->mArg0.mLabelIdx;
|
||||
// Speculative make it a short jump
|
||||
jump.mJumpKind = 0;
|
||||
jump.mCmpKind = inst->mArg1.mCmpKind;
|
||||
deferredJumps.push_back(jump);
|
||||
if (inst->mArg0.mKind == BeMCOperandKind_Immediate_i64)
|
||||
{
|
||||
mOut.Write(GetJumpOpCode(inst->mArg1.mCmpKind, false));
|
||||
mOut.Write((uint8)inst->mArg0.mImmediate);
|
||||
}
|
||||
else
|
||||
{
|
||||
BF_ASSERT(inst->mArg0.mKind == BeMCOperandKind_Label);
|
||||
BeMCJump jump;
|
||||
jump.mCodeOffset = funcCodePos;
|
||||
jump.mLabelIdx = inst->mArg0.mLabelIdx;
|
||||
// Speculative make it a short jump
|
||||
jump.mJumpKind = 0;
|
||||
jump.mCmpKind = inst->mArg1.mCmpKind;
|
||||
deferredJumps.push_back(jump);
|
||||
|
||||
mOut.Write(GetJumpOpCode(jump.mCmpKind, false));
|
||||
mOut.Write((uint8)0);
|
||||
mOut.Write(GetJumpOpCode(jump.mCmpKind, false));
|
||||
mOut.Write((uint8)0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BeMCInstKind_Br:
|
||||
|
@ -15857,7 +15966,7 @@ void BeMCContext::Print(bool showVRegFlags, bool showVRegDetails)
|
|||
OutputDebugStr(ToString(showVRegFlags, showVRegDetails));
|
||||
}
|
||||
|
||||
BeMCOperand BeMCContext::AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand& lhs, const BeMCOperand& rhs, BeMCBinIdentityKind identityKind)
|
||||
BeMCOperand BeMCContext::AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand& lhs, const BeMCOperand& rhs, BeMCBinIdentityKind identityKind, BeMCOverflowCheckKind overflowCheckKind)
|
||||
{
|
||||
if ((lhs.IsImmediate()) && (lhs.mKind == rhs.mKind))
|
||||
{
|
||||
|
@ -15918,6 +16027,13 @@ BeMCOperand BeMCContext::AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand&
|
|||
|
||||
auto mcInst = AllocInst(instKind, lhs, rhs);
|
||||
mcInst->mResult = result;
|
||||
|
||||
if (overflowCheckKind != BeMCOverflowCheckKind_None)
|
||||
{
|
||||
AllocInst(BeMCInstKind_CondBr, BeMCOperand::FromImmediate(1), BeMCOperand::FromCmpKind((overflowCheckKind == BeMCOverflowCheckKind_B) ? BeCmpKind_NB : BeCmpKind_NO));
|
||||
AllocInst(BeMCInstKind_DbgBreak);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -16399,9 +16515,18 @@ void BeMCContext::Generate(BeFunction* function)
|
|||
|
||||
switch (castedInst->mOpKind)
|
||||
{
|
||||
case BeBinaryOpKind_Add: result = AllocBinaryOp(BeMCInstKind_Add, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsZero); break;
|
||||
case BeBinaryOpKind_Subtract: result = AllocBinaryOp(BeMCInstKind_Sub, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsZero); break;
|
||||
case BeBinaryOpKind_Multiply: result = AllocBinaryOp(BeMCInstKind_IMul, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsOne); break;
|
||||
case BeBinaryOpKind_Add: result = AllocBinaryOp(BeMCInstKind_Add, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsZero,
|
||||
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? BeMCOverflowCheckKind_O :
|
||||
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Unsigned) != 0) ? BeMCOverflowCheckKind_B : BeMCOverflowCheckKind_None);
|
||||
break;
|
||||
case BeBinaryOpKind_Subtract: result = AllocBinaryOp(BeMCInstKind_Sub, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsZero,
|
||||
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? BeMCOverflowCheckKind_O :
|
||||
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Unsigned) != 0) ? BeMCOverflowCheckKind_B : BeMCOverflowCheckKind_None);
|
||||
break;
|
||||
case BeBinaryOpKind_Multiply: result = AllocBinaryOp(((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Unsigned) != 0) ? BeMCInstKind_Mul : BeMCInstKind_IMul, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsOne,
|
||||
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? BeMCOverflowCheckKind_O :
|
||||
((castedInst->mOverflowCheckKind & BfOverflowCheckKind_Unsigned) != 0) ? BeMCOverflowCheckKind_O : BeMCOverflowCheckKind_None);
|
||||
break;
|
||||
case BeBinaryOpKind_SDivide: result = AllocBinaryOp(BeMCInstKind_IDiv, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsOne); break;
|
||||
case BeBinaryOpKind_UDivide: result = AllocBinaryOp(BeMCInstKind_Div, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsOne); break;
|
||||
case BeBinaryOpKind_SModulus: result = AllocBinaryOp(BeMCInstKind_IRem, mcLHS, mcRHS, type->IsFloat() ? BeMCBinIdentityKind_None : BeMCBinIdentityKind_Right_IsOne_Result_Zero); break;
|
||||
|
|
|
@ -1293,6 +1293,13 @@ struct BeRMParamsInfo
|
|||
}
|
||||
};
|
||||
|
||||
enum BeMCOverflowCheckKind
|
||||
{
|
||||
BeMCOverflowCheckKind_None,
|
||||
BeMCOverflowCheckKind_B,
|
||||
BeMCOverflowCheckKind_O
|
||||
};
|
||||
|
||||
// This class only processes one function per instantiation
|
||||
class BeMCContext
|
||||
{
|
||||
|
@ -1367,7 +1374,7 @@ public:
|
|||
BeMCInst* AllocInst(BeMCInstKind instKind, const BeMCOperand& arg0, const BeMCOperand& arg1, int insertIdx = -1);
|
||||
void MergeInstFlags(BeMCInst* prevInst, BeMCInst* inst, BeMCInst* nextInst);
|
||||
void RemoveInst(BeMCBlock* block, int instIdx, bool needChangesMerged = true, bool removeFromList = true);
|
||||
BeMCOperand AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand & lhs, const BeMCOperand & rhs, BeMCBinIdentityKind identityKind);
|
||||
BeMCOperand AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand & lhs, const BeMCOperand & rhs, BeMCBinIdentityKind identityKind, BeMCOverflowCheckKind overflowCheckKind = BeMCOverflowCheckKind_None);
|
||||
BeMCOperand GetCallArgVReg(int argIdx, BeTypeCode typeCode);
|
||||
BeMCOperand CreateCall(const BeMCOperand& func, const SizedArrayImpl<BeMCOperand>& args, BeType* retType = NULL, BfIRCallingConv callingConv = BfIRCallingConv_CDecl, bool structRet = false, bool noReturn = false, bool isVarArg = false);
|
||||
BeMCOperand CreateCall(const BeMCOperand& func, const SizedArrayImpl<BeValue*>& args, BeType* retType = NULL, BfIRCallingConv callingConv = BfIRCallingConv_CDecl, bool structRet = false, bool noReturn = false, bool isVarArg = false);
|
||||
|
|
|
@ -1683,6 +1683,8 @@ void BeDumpContext::ToString(StringImpl& str, BeCmpKind cmpKind)
|
|||
case BeCmpKind_UGT: str += "ugt"; return;
|
||||
case BeCmpKind_SGE: str += "sge"; return;
|
||||
case BeCmpKind_UGE: str += "uge"; return;
|
||||
case BeCmpKind_NB: str += "nb"; return;
|
||||
case BeCmpKind_NO: str += "no"; return;
|
||||
default:
|
||||
str += "???";
|
||||
}
|
||||
|
@ -3292,7 +3294,7 @@ BeCmpInst* BeModule::CreateCmp(BeCmpKind cmpKind, BeValue* lhs, BeValue* rhs)
|
|||
return inst;
|
||||
}
|
||||
|
||||
BeBinaryOpInst* BeModule::CreateBinaryOp(BeBinaryOpKind opKind, BeValue* lhs, BeValue* rhs)
|
||||
BeBinaryOpInst* BeModule::CreateBinaryOp(BeBinaryOpKind opKind, BeValue* lhs, BeValue* rhs, BfOverflowCheckKind overflowCheckKind)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
auto leftType = lhs->GetType();
|
||||
|
@ -3303,6 +3305,7 @@ BeBinaryOpInst* BeModule::CreateBinaryOp(BeBinaryOpKind opKind, BeValue* lhs, Be
|
|||
inst->mOpKind = opKind;
|
||||
inst->mLHS = lhs;
|
||||
inst->mRHS = rhs;
|
||||
inst->mOverflowCheckKind = overflowCheckKind;
|
||||
AddInst(inst);
|
||||
return inst;
|
||||
}
|
||||
|
|
|
@ -820,6 +820,7 @@ public:
|
|||
BE_VALUE_TYPE(BeBinaryOpInst, BeInst);
|
||||
|
||||
BeBinaryOpKind mOpKind;
|
||||
BfOverflowCheckKind mOverflowCheckKind;
|
||||
BeValue* mLHS;
|
||||
BeValue* mRHS;
|
||||
|
||||
|
@ -829,6 +830,7 @@ public:
|
|||
{
|
||||
hashCtx.Mixin(TypeId);
|
||||
hashCtx.Mixin(mOpKind);
|
||||
hashCtx.Mixin(mOverflowCheckKind);
|
||||
mLHS->HashReference(hashCtx);
|
||||
mRHS->HashReference(hashCtx);
|
||||
}
|
||||
|
@ -847,7 +849,9 @@ enum BeCmpKind
|
|||
BeCmpKind_SGT,
|
||||
BeCmpKind_UGT,
|
||||
BeCmpKind_SGE,
|
||||
BeCmpKind_UGE
|
||||
BeCmpKind_UGE,
|
||||
BeCmpKind_NB,
|
||||
BeCmpKind_NO,
|
||||
};
|
||||
|
||||
class BeCmpInst : public BeInst
|
||||
|
@ -2338,7 +2342,7 @@ public:
|
|||
BeNumericCastInst* CreateNumericCast(BeValue* value, BeType* toType, bool valSigned, bool toSigned);
|
||||
BeBitCastInst* CreateBitCast(BeValue* value, BeType* toType);;
|
||||
BeCmpInst* CreateCmp(BeCmpKind cmpKind, BeValue* lhs, BeValue* rhs);
|
||||
BeBinaryOpInst* CreateBinaryOp(BeBinaryOpKind opKind, BeValue* lhs, BeValue* rhs);
|
||||
BeBinaryOpInst* CreateBinaryOp(BeBinaryOpKind opKind, BeValue* lhs, BeValue* rhs, BfOverflowCheckKind overflowCheckKind = BfOverflowCheckKind_None);
|
||||
|
||||
BeAllocaInst* CreateAlloca(BeType* type);
|
||||
BeLoadInst* CreateLoad(BeValue* value, bool isVolatile);
|
||||
|
|
|
@ -9729,7 +9729,8 @@ BF_EXPORT void BF_CALLTYPE BfCompiler_SetOptions(BfCompiler* bfCompiler, BfProje
|
|||
// }
|
||||
BF_ASSERT(!options->mEnableRealtimeLeakCheck);
|
||||
#endif
|
||||
options->mEmitObjectAccessCheck = (optionFlags & BfCompilerOptionFlag_EmitDebugInfo) != 0;
|
||||
options->mEmitObjectAccessCheck = (optionFlags & BfCompilerOptionFlag_EmitObjectAccessCheck) != 0;
|
||||
options->mArithmeticChecks = (optionFlags & BfCompilerOptionFlag_ArithmeticChecks) != 0;
|
||||
options->mAllocStackCount = allocStackCount;
|
||||
|
||||
if (hotProject != NULL)
|
||||
|
@ -9770,6 +9771,7 @@ BF_EXPORT void BF_CALLTYPE BfCompiler_SetOptions(BfCompiler* bfCompiler, BfProje
|
|||
options->mObjectHasDebugFlags = false;
|
||||
options->mEnableRealtimeLeakCheck = false;
|
||||
options->mEmitObjectAccessCheck = false;
|
||||
options->mArithmeticChecks = false;
|
||||
options->mEmitDynamicCastCheck = false;
|
||||
options->mRuntimeChecks = (optionFlags & BfCompilerOptionFlag_RuntimeChecks) != 0;
|
||||
}
|
||||
|
|
|
@ -117,7 +117,8 @@ public:
|
|||
bool mAllowHotSwapping;
|
||||
bool mObjectHasDebugFlags;
|
||||
bool mEnableRealtimeLeakCheck;
|
||||
bool mEmitObjectAccessCheck; // Only valid with mObjectHasDebugFlags
|
||||
bool mEmitObjectAccessCheck; // Only valid with mObjectHasDebugFlags
|
||||
bool mArithmeticChecks;
|
||||
bool mEnableCustodian;
|
||||
bool mEnableSideStack;
|
||||
bool mHasVDataExtender;
|
||||
|
@ -162,6 +163,7 @@ public:
|
|||
mEmitDynamicCastCheck = true;
|
||||
mAllowHotSwapping = false;
|
||||
mEmitObjectAccessCheck = false;
|
||||
mArithmeticChecks = false;
|
||||
mObjectHasDebugFlags = false;
|
||||
mEnableRealtimeLeakCheck = false;
|
||||
mWriteIR = false;
|
||||
|
|
|
@ -2200,6 +2200,7 @@ void BfContext::UpdateRevisedTypes()
|
|||
workspaceConfigHashCtx.Mixin(options->mObjectHasDebugFlags);
|
||||
workspaceConfigHashCtx.Mixin(options->mEnableRealtimeLeakCheck);
|
||||
workspaceConfigHashCtx.Mixin(options->mEmitObjectAccessCheck);
|
||||
workspaceConfigHashCtx.Mixin(options->mArithmeticChecks);
|
||||
workspaceConfigHashCtx.Mixin(options->mEnableCustodian);
|
||||
workspaceConfigHashCtx.Mixin(options->mEnableSideStack);
|
||||
workspaceConfigHashCtx.Mixin(options->mHasVDataExtender);
|
||||
|
|
|
@ -19769,7 +19769,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
|
|||
|
||||
bool wantsChecks = checkedKind == BfCheckedKind_Checked;
|
||||
if (checkedKind == BfCheckedKind_NotSet)
|
||||
wantsChecks = mModule->GetDefaultCheckedKind() == BfCheckedKind_Checked;
|
||||
wantsChecks = mModule->GetDefaultCheckedKind() == BfCheckedKind_Checked;
|
||||
|
||||
//target.mType = mModule->ResolveGenericType(target.mType);
|
||||
if (target.mType->IsVar())
|
||||
|
@ -22665,23 +22665,43 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL
|
|||
return;
|
||||
}
|
||||
|
||||
auto _GetOverflowKind = [&](bool wantOverflow)
|
||||
{
|
||||
if (!wantOverflow)
|
||||
return BfOverflowCheckKind_None;
|
||||
if (mModule->GetDefaultCheckedKind() != BfCheckedKind_Checked)
|
||||
return BfOverflowCheckKind_None;
|
||||
|
||||
bool arithmeticChecks = mModule->mCompiler->mOptions.mArithmeticChecks;
|
||||
auto typeOptions = mModule->GetTypeOptions();
|
||||
if (typeOptions != NULL)
|
||||
arithmeticChecks = typeOptions->Apply(arithmeticChecks, BfOptionFlags_ArithmeticCheck);
|
||||
if (!arithmeticChecks)
|
||||
return BfOverflowCheckKind_None;
|
||||
|
||||
BfOverflowCheckKind overflowCheckKind = (resultType->IsSigned()) ? BfOverflowCheckKind_Signed : BfOverflowCheckKind_Unsigned;
|
||||
if (!mModule->IsOptimized())
|
||||
overflowCheckKind = (BfOverflowCheckKind)(overflowCheckKind | BfOverflowCheckKind_Flag_UseAsm);
|
||||
return overflowCheckKind;
|
||||
};
|
||||
|
||||
switch (binaryOp)
|
||||
{
|
||||
case BfBinaryOp_Add:
|
||||
case BfBinaryOp_OverflowAdd:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateAdd(convLeftValue, convRightValue), resultType);
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateAdd(convLeftValue, convRightValue, _GetOverflowKind(binaryOp == BfBinaryOp_Add)), resultType);
|
||||
if (binaryOp != BfBinaryOp_OverflowAdd)
|
||||
mModule->CheckRangeError(resultType, opToken);
|
||||
break;
|
||||
case BfBinaryOp_Subtract:
|
||||
case BfBinaryOp_OverflowSubtract:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateSub(convLeftValue, convRightValue), resultType);
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateSub(convLeftValue, convRightValue, _GetOverflowKind(binaryOp == BfBinaryOp_Subtract)), resultType);
|
||||
if (binaryOp != BfBinaryOp_OverflowSubtract)
|
||||
mModule->CheckRangeError(resultType, opToken);
|
||||
break;
|
||||
case BfBinaryOp_Multiply:
|
||||
case BfBinaryOp_OverflowMultiply:
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateMul(convLeftValue, convRightValue), resultType);
|
||||
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateMul(convLeftValue, convRightValue, _GetOverflowKind(binaryOp == BfBinaryOp_Multiply)), resultType);
|
||||
if (binaryOp != BfBinaryOp_OverflowMultiply)
|
||||
mModule->CheckRangeError(resultType, opToken);
|
||||
break;
|
||||
|
|
|
@ -4248,7 +4248,7 @@ BfIRValue BfIRBuilder::CreateCmpGTE(BfIRValue lhs, BfIRValue rhs, bool isSigned)
|
|||
return retVal;
|
||||
}
|
||||
|
||||
BfIRValue BfIRBuilder::CreateAdd(BfIRValue lhs, BfIRValue rhs)
|
||||
BfIRValue BfIRBuilder::CreateAdd(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind)
|
||||
{
|
||||
mOpFailed = false;
|
||||
if ((lhs.IsConst()) && (rhs.IsConst()))
|
||||
|
@ -4260,12 +4260,19 @@ BfIRValue BfIRBuilder::CreateAdd(BfIRValue lhs, BfIRValue rhs)
|
|||
}
|
||||
}
|
||||
|
||||
auto retVal = WriteCmd(BfIRCmd_Add, lhs, rhs);
|
||||
auto retVal = WriteCmd(BfIRCmd_Add, lhs, rhs, overflowCheckKind);
|
||||
NEW_CMD_INSERTED_IRVALUE;
|
||||
|
||||
if ((overflowCheckKind != BfOverflowCheckKind_None) && (!mIgnoreWrites))
|
||||
{
|
||||
mInsertBlock = mActualInsertBlock = WriteCmd(BfIRCmd_GetInsertBlock);
|
||||
NEW_CMD_INSERTED_IRVALUE;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
BfIRValue BfIRBuilder::CreateSub(BfIRValue lhs, BfIRValue rhs)
|
||||
BfIRValue BfIRBuilder::CreateSub(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind)
|
||||
{
|
||||
mOpFailed = false;
|
||||
if ((lhs.IsConst()) && (rhs.IsConst()))
|
||||
|
@ -4273,12 +4280,19 @@ BfIRValue BfIRBuilder::CreateSub(BfIRValue lhs, BfIRValue rhs)
|
|||
BINOPFUNC_APPLY(lhs, rhs, CheckedSub);
|
||||
}
|
||||
|
||||
auto retVal = WriteCmd(BfIRCmd_Sub, lhs, rhs);
|
||||
auto retVal = WriteCmd(BfIRCmd_Sub, lhs, rhs, overflowCheckKind);
|
||||
NEW_CMD_INSERTED;
|
||||
|
||||
if ((overflowCheckKind != BfOverflowCheckKind_None) && (!mIgnoreWrites))
|
||||
{
|
||||
mInsertBlock = mActualInsertBlock = WriteCmd(BfIRCmd_GetInsertBlock);
|
||||
NEW_CMD_INSERTED_IRVALUE;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
BfIRValue BfIRBuilder::CreateMul(BfIRValue lhs, BfIRValue rhs)
|
||||
BfIRValue BfIRBuilder::CreateMul(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind)
|
||||
{
|
||||
mOpFailed = false;
|
||||
if ((lhs.IsConst()) && (rhs.IsConst()))
|
||||
|
@ -4286,8 +4300,15 @@ BfIRValue BfIRBuilder::CreateMul(BfIRValue lhs, BfIRValue rhs)
|
|||
BINOPFUNC_APPLY(lhs, rhs, CheckedMul);
|
||||
}
|
||||
|
||||
auto retVal = WriteCmd(BfIRCmd_Mul, lhs, rhs);
|
||||
auto retVal = WriteCmd(BfIRCmd_Mul, lhs, rhs, overflowCheckKind);
|
||||
NEW_CMD_INSERTED_IRVALUE;
|
||||
|
||||
if ((overflowCheckKind != BfOverflowCheckKind_None) && (!mIgnoreWrites))
|
||||
{
|
||||
mInsertBlock = mActualInsertBlock = WriteCmd(BfIRCmd_GetInsertBlock);
|
||||
NEW_CMD_INSERTED_IRVALUE;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@ -5394,7 +5415,7 @@ void BfIRBuilder::CreateStatementStart()
|
|||
}
|
||||
|
||||
void BfIRBuilder::CreateObjectAccessCheck(BfIRValue value, bool useAsm)
|
||||
{
|
||||
{
|
||||
auto retBlock = WriteCmd(BfIRCmd_ObjectAccessCheck, value, useAsm);
|
||||
NEW_CMD_INSERTED_IRBLOCK;
|
||||
if (!mIgnoreWrites)
|
||||
|
|
|
@ -174,7 +174,7 @@ enum BfIRCmd : uint8
|
|||
|
||||
BfIRCmd_SetName,
|
||||
BfIRCmd_CreateUndefValue,
|
||||
BfIRCmd_NumericCast,
|
||||
BfIRCmd_NumericCast,
|
||||
BfIRCmd_CmpEQ,
|
||||
BfIRCmd_CmpNE,
|
||||
BfIRCmd_CmpSLT,
|
||||
|
@ -247,6 +247,7 @@ enum BfIRCmd : uint8
|
|||
BfIRCmd_AddBlock,
|
||||
BfIRCmd_DropBlocks,
|
||||
BfIRCmd_MergeBlockDown,
|
||||
BfIRCmd_GetInsertBlock,
|
||||
BfIRCmd_SetInsertPoint,
|
||||
BfIRCmd_SetInsertPointAtStart,
|
||||
BfIRCmd_EraseFromParent,
|
||||
|
@ -964,6 +965,14 @@ struct BfIRState
|
|||
Array<BfFilePosition> mSavedDebugLocs;
|
||||
};
|
||||
|
||||
enum BfOverflowCheckKind : int8
|
||||
{
|
||||
BfOverflowCheckKind_None = 0,
|
||||
BfOverflowCheckKind_Signed = 1,
|
||||
BfOverflowCheckKind_Unsigned = 2,
|
||||
BfOverflowCheckKind_Flag_UseAsm = 4
|
||||
};
|
||||
|
||||
class BfIRBuilder : public BfIRConstHolder
|
||||
{
|
||||
public:
|
||||
|
@ -1182,9 +1191,9 @@ public:
|
|||
BfIRValue CreateCmpLTE(BfIRValue lhs, BfIRValue rhs, bool isSigned);
|
||||
BfIRValue CreateCmpGT(BfIRValue lhs, BfIRValue rhs, bool isSigned);
|
||||
BfIRValue CreateCmpGTE(BfIRValue lhs, BfIRValue rhs, bool isSigned);
|
||||
BfIRValue CreateAdd(BfIRValue lhs, BfIRValue rhs);
|
||||
BfIRValue CreateSub(BfIRValue lhs, BfIRValue rhs);
|
||||
BfIRValue CreateMul(BfIRValue lhs, BfIRValue rhs);
|
||||
BfIRValue CreateAdd(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind = BfOverflowCheckKind_None);
|
||||
BfIRValue CreateSub(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind = BfOverflowCheckKind_None);
|
||||
BfIRValue CreateMul(BfIRValue lhs, BfIRValue rhs, BfOverflowCheckKind overflowCheckKind = BfOverflowCheckKind_None);
|
||||
BfIRValue CreateDiv(BfIRValue lhs, BfIRValue rhs, bool isSigned);
|
||||
BfIRValue CreateRem(BfIRValue lhs, BfIRValue rhs, bool isSigned);
|
||||
BfIRValue CreateAnd(BfIRValue lhs, BfIRValue rhs);
|
||||
|
|
|
@ -340,7 +340,8 @@ BfIRCodeGen::BfIRCodeGen()
|
|||
mLLVMTargetMachine = NULL;
|
||||
|
||||
mNopInlineAsm = NULL;
|
||||
mAsmObjectCheckAsm = NULL;
|
||||
mObjectCheckAsm = NULL;
|
||||
mOverflowCheckAsm = NULL;
|
||||
mHasDebugLoc = false;
|
||||
mAttrSet = NULL;
|
||||
mIRBuilder = NULL;
|
||||
|
@ -730,6 +731,11 @@ void BfIRCodeGen::Read(bool& val)
|
|||
val = mStream->Read() != 0;
|
||||
}
|
||||
|
||||
void BfIRCodeGen::Read(int8& val)
|
||||
{
|
||||
val = mStream->Read();
|
||||
}
|
||||
|
||||
void BfIRCodeGen::Read(BfIRTypeEntry*& type)
|
||||
{
|
||||
int typeId = (int)ReadSLEB128();
|
||||
|
@ -1447,6 +1453,72 @@ llvm::Value* BfIRCodeGen::FixGEP(llvm::Value* fromValue, llvm::Value* result)
|
|||
return result;
|
||||
}
|
||||
|
||||
llvm::Value* BfIRCodeGen::DoCheckedIntrinsic(llvm::Intrinsic::ID intrin, llvm::Value* lhs, llvm::Value* rhs, bool useAsm)
|
||||
{
|
||||
if ((mTargetTriple.GetMachineType() != BfMachineType_x86) && (mTargetTriple.GetMachineType() != BfMachineType_x64))
|
||||
useAsm = false;
|
||||
|
||||
CmdParamVec<llvm::Type*> useParams;
|
||||
useParams.push_back(lhs->getType());
|
||||
auto func = llvm::Intrinsic::getDeclaration(mLLVMModule, intrin, useParams);
|
||||
|
||||
CmdParamVec<llvm::Value*> args;
|
||||
args.push_back(lhs);
|
||||
args.push_back(rhs);
|
||||
llvm::FunctionType* funcType = NULL;
|
||||
if (auto ptrType = llvm::dyn_cast<llvm::PointerType>(func->getType()))
|
||||
funcType = llvm::dyn_cast<llvm::FunctionType>(ptrType->getElementType());
|
||||
auto aggResult = mIRBuilder->CreateCall(funcType, func, args);
|
||||
auto valResult = mIRBuilder->CreateExtractValue(aggResult, 0);
|
||||
auto failResult = mIRBuilder->CreateExtractValue(aggResult, 1);
|
||||
|
||||
if (!useAsm)
|
||||
{
|
||||
mLockedBlocks.Add(mIRBuilder->GetInsertBlock());
|
||||
|
||||
auto failBB = llvm::BasicBlock::Create(*mLLVMContext, "access.fail");
|
||||
auto passBB = llvm::BasicBlock::Create(*mLLVMContext, "access.pass");
|
||||
|
||||
mIRBuilder->CreateCondBr(failResult, failBB, passBB);
|
||||
|
||||
mActiveFunction->getBasicBlockList().push_back(failBB);
|
||||
mIRBuilder->SetInsertPoint(failBB);
|
||||
|
||||
auto trapDecl = llvm::Intrinsic::getDeclaration(mLLVMModule, llvm::Intrinsic::trap);
|
||||
auto callInst = mIRBuilder->CreateCall(trapDecl);
|
||||
callInst->addAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::NoReturn);
|
||||
mIRBuilder->CreateBr(passBB);
|
||||
|
||||
mActiveFunction->getBasicBlockList().push_back(passBB);
|
||||
mIRBuilder->SetInsertPoint(passBB);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mOverflowCheckAsm == NULL)
|
||||
{
|
||||
std::vector<llvm::Type*> paramTypes;
|
||||
paramTypes.push_back(llvm::Type::getInt8Ty(*mLLVMContext));
|
||||
auto funcType = llvm::FunctionType::get(llvm::Type::getVoidTy(*mLLVMContext), paramTypes, false);
|
||||
|
||||
String asmStr =
|
||||
"testb $$1, $0\n"
|
||||
"jz 1f\n"
|
||||
"int $$3\n"
|
||||
"1:";
|
||||
|
||||
mOverflowCheckAsm = llvm::InlineAsm::get(funcType,
|
||||
asmStr.c_str(), "r,~{dirflag},~{fpsr},~{flags}", true,
|
||||
false, llvm::InlineAsm::AD_ATT);
|
||||
}
|
||||
|
||||
llvm::SmallVector<llvm::Value*, 1> llvmArgs;
|
||||
llvmArgs.push_back(mIRBuilder->CreateIntCast(failResult, llvm::Type::getInt8Ty(*mLLVMContext), false));
|
||||
llvm::CallInst* callInst = mIRBuilder->CreateCall(mOverflowCheckAsm, llvmArgs);
|
||||
callInst->addAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::NoUnwind);
|
||||
}
|
||||
return valResult;
|
||||
}
|
||||
|
||||
void BfIRCodeGen::CreateMemSet(llvm::Value* addr, llvm::Value* val, llvm::Value* size, int alignment, bool isVolatile)
|
||||
{
|
||||
auto sizeConst = llvm::dyn_cast<llvm::ConstantInt>(size);
|
||||
|
@ -2040,22 +2112,31 @@ void BfIRCodeGen::HandleNextCmd()
|
|||
SetResult(curId, mIRBuilder->CreateICmpUGE(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
|
||||
case BfIRCmd_Add:
|
||||
{
|
||||
CMD_PARAM(llvm::Value*, lhs);
|
||||
CMD_PARAM(llvm::Value*, rhs);
|
||||
CMD_PARAM(int8, overflowCheckKind);
|
||||
if (lhs->getType()->isFloatingPointTy())
|
||||
SetResult(curId, mIRBuilder->CreateFAdd(lhs, rhs));
|
||||
else if ((overflowCheckKind & (BfOverflowCheckKind_Signed | BfOverflowCheckKind_Unsigned)) != 0)
|
||||
SetResult(curId, DoCheckedIntrinsic(((overflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? llvm::Intrinsic::sadd_with_overflow : llvm::Intrinsic::uadd_with_overflow,
|
||||
lhs, rhs, (overflowCheckKind & BfOverflowCheckKind_Flag_UseAsm) != 0));
|
||||
else
|
||||
SetResult(curId, mIRBuilder->CreateAdd(lhs, rhs));
|
||||
SetResult(curId, mIRBuilder->CreateAdd(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
case BfIRCmd_Sub:
|
||||
{
|
||||
CMD_PARAM(llvm::Value*, lhs);
|
||||
CMD_PARAM(llvm::Value*, rhs);
|
||||
CMD_PARAM(int8, overflowCheckKind);
|
||||
if (lhs->getType()->isFloatingPointTy())
|
||||
SetResult(curId, mIRBuilder->CreateFSub(lhs, rhs));
|
||||
else if ((overflowCheckKind & (BfOverflowCheckKind_Signed | BfOverflowCheckKind_Unsigned)) != 0)
|
||||
SetResult(curId, DoCheckedIntrinsic(((overflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? llvm::Intrinsic::ssub_with_overflow : llvm::Intrinsic::usub_with_overflow,
|
||||
lhs, rhs, (overflowCheckKind & BfOverflowCheckKind_Flag_UseAsm) != 0));
|
||||
else
|
||||
SetResult(curId, mIRBuilder->CreateSub(lhs, rhs));
|
||||
}
|
||||
|
@ -2064,8 +2145,12 @@ void BfIRCodeGen::HandleNextCmd()
|
|||
{
|
||||
CMD_PARAM(llvm::Value*, lhs);
|
||||
CMD_PARAM(llvm::Value*, rhs);
|
||||
CMD_PARAM(int8, overflowCheckKind);
|
||||
if (lhs->getType()->isFloatingPointTy())
|
||||
SetResult(curId, mIRBuilder->CreateFMul(lhs, rhs));
|
||||
else if ((overflowCheckKind & (BfOverflowCheckKind_Signed | BfOverflowCheckKind_Unsigned)) != 0)
|
||||
SetResult(curId, DoCheckedIntrinsic(((overflowCheckKind & BfOverflowCheckKind_Signed) != 0) ? llvm::Intrinsic::smul_with_overflow : llvm::Intrinsic::umul_with_overflow,
|
||||
lhs, rhs, (overflowCheckKind & BfOverflowCheckKind_Flag_UseAsm) != 0));
|
||||
else
|
||||
SetResult(curId, mIRBuilder->CreateMul(lhs, rhs));
|
||||
}
|
||||
|
@ -2528,7 +2613,12 @@ void BfIRCodeGen::HandleNextCmd()
|
|||
intoInstList.splice(intoInstList.begin(), fromInstList, fromInstList.begin(), fromInstList.end());
|
||||
fromBlock->eraseFromParent();
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case BfIRCmd_GetInsertBlock:
|
||||
{
|
||||
SetResult(curId, mIRBuilder->GetInsertBlock());
|
||||
}
|
||||
break;
|
||||
case BfIRCmd_SetInsertPoint:
|
||||
{
|
||||
CMD_PARAM(llvm::BasicBlock*, block);
|
||||
|
@ -2542,7 +2632,7 @@ void BfIRCodeGen::HandleNextCmd()
|
|||
CMD_PARAM(llvm::BasicBlock*, block);
|
||||
mIRBuilder->SetInsertPoint(block, block->begin());
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case BfIRCmd_EraseFromParent:
|
||||
{
|
||||
CMD_PARAM(llvm::BasicBlock*, block);
|
||||
|
@ -3906,7 +3996,7 @@ void BfIRCodeGen::HandleNextCmd()
|
|||
else
|
||||
{
|
||||
llvm::Type* voidPtrType = llvm::Type::getInt8PtrTy(*mLLVMContext);
|
||||
if (mAsmObjectCheckAsm == NULL)
|
||||
if (mObjectCheckAsm == NULL)
|
||||
{
|
||||
std::vector<llvm::Type*> paramTypes;
|
||||
paramTypes.push_back(voidPtrType);
|
||||
|
@ -3918,7 +4008,7 @@ void BfIRCodeGen::HandleNextCmd()
|
|||
"int $$3\n"
|
||||
"1:";
|
||||
|
||||
mAsmObjectCheckAsm = llvm::InlineAsm::get(funcType,
|
||||
mObjectCheckAsm = llvm::InlineAsm::get(funcType,
|
||||
asmStr.c_str(), "r,~{dirflag},~{fpsr},~{flags}", true,
|
||||
false, llvm::InlineAsm::AD_ATT);
|
||||
}
|
||||
|
@ -3926,7 +4016,7 @@ void BfIRCodeGen::HandleNextCmd()
|
|||
llvm::SmallVector<llvm::Value*, 1> llvmArgs;
|
||||
llvmArgs.push_back(mIRBuilder->CreateBitCast(val, voidPtrType));
|
||||
|
||||
llvm::CallInst* callInst = irBuilder->CreateCall(mAsmObjectCheckAsm, llvmArgs);
|
||||
llvm::CallInst* callInst = irBuilder->CreateCall(mObjectCheckAsm, llvmArgs);
|
||||
callInst->addAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::NoUnwind);
|
||||
|
||||
SetResult(curId, mIRBuilder->GetInsertBlock());
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace llvm
|
|||
class AttributeList;
|
||||
class Module;
|
||||
class LLVMContext;
|
||||
class TargetMachine;
|
||||
class TargetMachine;
|
||||
};
|
||||
|
||||
NS_BF_BEGIN
|
||||
|
@ -100,7 +100,8 @@ public:
|
|||
llvm::TargetMachine* mLLVMTargetMachine;
|
||||
Array<llvm::DebugLoc> mSavedDebugLocs;
|
||||
llvm::InlineAsm* mNopInlineAsm;
|
||||
llvm::InlineAsm* mAsmObjectCheckAsm;
|
||||
llvm::InlineAsm* mObjectCheckAsm;
|
||||
llvm::InlineAsm* mOverflowCheckAsm;
|
||||
llvm::DebugLoc mDebugLoc;
|
||||
BfCodeGenOptions mCodeGenOptions;
|
||||
bool mHasDebugLoc;
|
||||
|
@ -140,6 +141,7 @@ public:
|
|||
llvm::Type* GetSizeAlignedType(BfIRTypeEntry* typeEntry);
|
||||
llvm::Value* GetAlignedPtr(llvm::Value* val);
|
||||
llvm::Value* FixGEP(llvm::Value* fromValue, llvm::Value* result);
|
||||
llvm::Value* DoCheckedIntrinsic(llvm::Intrinsic::ID intrin, llvm::Value* lhs, llvm::Value* rhs, bool useAsm);
|
||||
|
||||
public:
|
||||
BfIRCodeGen();
|
||||
|
@ -158,6 +160,7 @@ public:
|
|||
void Read(int64& i);
|
||||
void Read(Val128& i);
|
||||
void Read(bool& val);
|
||||
void Read(int8& val);
|
||||
void Read(BfIRTypeEntry*& type);
|
||||
void Read(llvm::Type*& llvmType, BfIRTypeEntry** outTypeEntry = NULL);
|
||||
void Read(llvm::FunctionType*& llvmType);
|
||||
|
|
|
@ -160,6 +160,7 @@ enum BfCompilerOptionFlags
|
|||
BfCompilerOptionFlag_DebugAlloc = 0x8000,
|
||||
BfCompilerOptionFlag_OmitDebugHelpers = 0x10000,
|
||||
BfCompilerOptionFlag_NoFramePointerElim = 0x20000,
|
||||
BfCompilerOptionFlag_ArithmeticChecks = 0x40000,
|
||||
};
|
||||
|
||||
enum BfTypeFlags
|
||||
|
@ -1441,19 +1442,20 @@ enum BfOptionFlags
|
|||
BfOptionFlags_InitLocalVariables = 2,
|
||||
BfOptionFlags_EmitDynamicCastCheck = 4,
|
||||
BfOptionFlags_EmitObjectAccessCheck = 8,
|
||||
BfOptionFlags_ArithmeticCheck = 0x10,
|
||||
|
||||
BfOptionFlags_ReflectAlwaysIncludeType = 0x10,
|
||||
BfOptionFlags_ReflectAlwaysIncludeAll = 0x20,
|
||||
BfOptionFlags_ReflectAssumeInstantiated = 0x40,
|
||||
BfOptionFlags_ReflectBoxing = 0x80,
|
||||
BfOptionFlags_ReflectStaticFields = 0x100,
|
||||
BfOptionFlags_ReflectNonStaticFields = 0x200,
|
||||
BfOptionFlags_ReflectStaticMethods = 0x400,
|
||||
BfOptionFlags_ReflectNonStaticMethods = 0x800,
|
||||
BfOptionFlags_ReflectConstructors = 0x1000,
|
||||
BfOptionFlags_ReflectAlwaysIncludeType = 0x20,
|
||||
BfOptionFlags_ReflectAlwaysIncludeAll = 0x40,
|
||||
BfOptionFlags_ReflectAssumeInstantiated = 0x80,
|
||||
BfOptionFlags_ReflectBoxing = 0x100,
|
||||
BfOptionFlags_ReflectStaticFields = 0x200,
|
||||
BfOptionFlags_ReflectNonStaticFields = 0x400,
|
||||
BfOptionFlags_ReflectStaticMethods = 0x800,
|
||||
BfOptionFlags_ReflectNonStaticMethods = 0x1000,
|
||||
BfOptionFlags_ReflectConstructors = 0x2000,
|
||||
|
||||
BfOptionFlags_Reflect_MethodMask = BfOptionFlags_ReflectStaticMethods | BfOptionFlags_ReflectNonStaticMethods | BfOptionFlags_ReflectConstructors,
|
||||
BfOptionFlags_Mask = 0xFFF
|
||||
BfOptionFlags_Mask = 0x3FFF
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -61,4 +61,11 @@ enum DbgAddrType : uint8
|
|||
DbgAddrType_Alias
|
||||
};
|
||||
|
||||
enum DbgBreakKind
|
||||
{
|
||||
DbgBreakKind_None,
|
||||
DbgBreakKind_ObjectAccess,
|
||||
DbgBreakKind_ArithmeticOverflow
|
||||
};
|
||||
|
||||
NS_BF_END
|
|
@ -2449,18 +2449,18 @@ bool DebugTarget::DecodeInstruction(addr_target address, CPUInst* inst)
|
|||
|
||||
}
|
||||
|
||||
bool DebugTarget::IsObjectAccessBreak(addr_target address, CPURegisters* registers, intptr_target* objAddr)
|
||||
DbgBreakKind DebugTarget::GetDbgBreakKind(addr_target address, CPURegisters* registers, intptr_target* objAddr)
|
||||
{
|
||||
for (auto dwarf : mDbgModules)
|
||||
{
|
||||
if ((address >= dwarf->mImageBase) && (address < dwarf->mImageBase + dwarf->mImageSize) && (dwarf->mOrigImageData != NULL))
|
||||
{
|
||||
bool result = mDebugger->mCPU->IsObjectAccessBreak(address, dwarf->mOrigImageData, registers->mIntRegsArray, objAddr);
|
||||
auto result = mDebugger->mCPU->GetDbgBreakKind(address, dwarf->mOrigImageData, registers->mIntRegsArray, objAddr);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return DbgBreakKind_None;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ public:
|
|||
|
||||
const DbgMemoryFlags ReadOrigImageData(addr_target address, uint8* data, int size);
|
||||
bool DecodeInstruction(addr_target address, CPUInst* inst);
|
||||
bool IsObjectAccessBreak(addr_target address, CPURegisters* regs, intptr_target* objAddr);
|
||||
DbgBreakKind GetDbgBreakKind(addr_target address, CPURegisters* regs, intptr_target* objAddr);
|
||||
DbgModule* FindDbgModuleForAddress(addr_target address);
|
||||
DbgModule* GetMainDbgModule();
|
||||
void ReportMemory(MemReporter* memReporter);
|
||||
|
|
|
@ -4866,7 +4866,8 @@ void WinDebugger::CheckNonDebuggerBreak()
|
|||
}
|
||||
|
||||
intptr_target objAddr;
|
||||
if (mDebugTarget->IsObjectAccessBreak(pcAddress, ®isters, &objAddr))
|
||||
auto dbgBreakKind = mDebugTarget->GetDbgBreakKind(pcAddress, ®isters, &objAddr);
|
||||
if (dbgBreakKind == DbgBreakKind_ObjectAccess)
|
||||
{
|
||||
String errorStr = "error Attempted to access deleted object";
|
||||
String objectAddr = EncodeDataPtr((addr_target)objAddr, true);
|
||||
|
@ -4874,6 +4875,12 @@ void WinDebugger::CheckNonDebuggerBreak()
|
|||
mDebugManager->mOutMessages.push_back(errorStr);
|
||||
return;
|
||||
}
|
||||
else if (dbgBreakKind == DbgBreakKind_ArithmeticOverflow)
|
||||
{
|
||||
String errorStr = "error Arithmetic overflow detected";
|
||||
mDebugManager->mOutMessages.push_back(errorStr);
|
||||
return;
|
||||
}
|
||||
|
||||
bool showMainThread = false;
|
||||
|
||||
|
|
|
@ -985,7 +985,7 @@ String X64CPU::InstructionToString(X64Instr* inst, uint64 addr)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool X64CPU::IsObjectAccessBreak(uint64 address, DbgModuleMemoryCache* memoryCache, int64* regs, int64* outObjectPtr)
|
||||
DbgBreakKind X64CPU::GetDbgBreakKind(uint64 address, DbgModuleMemoryCache* memoryCache, int64* regs, int64* outObjectPtr)
|
||||
{
|
||||
// We've looking for a CMP BYTE PTR [<reg>], -0x80
|
||||
// if <reg> is R12 then encoding takes an extra 2 bytes
|
||||
|
@ -1005,6 +1005,19 @@ bool X64CPU::IsObjectAccessBreak(uint64 address, DbgModuleMemoryCache* memoryCac
|
|||
continue;
|
||||
|
||||
auto immediateType = (instDesc.TSFlags & llvm::X86II::ImmMask);
|
||||
if ((immediateType == llvm::X86II::Imm8) && (inst.mMCInst.getNumOperands() == 2))
|
||||
{
|
||||
// We're checking for a TEST [<reg>], 1
|
||||
if (inst.mMCInst.getOpcode() != llvm::X86::TEST8ri)
|
||||
continue;
|
||||
auto immOp = inst.mMCInst.getOperand(1);
|
||||
if (!immOp.isImm())
|
||||
continue;
|
||||
if (immOp.getImm() != 1)
|
||||
continue;
|
||||
return DbgBreakKind_ArithmeticOverflow;
|
||||
}
|
||||
|
||||
if ((immediateType == 0) || (inst.mMCInst.getNumOperands() < 6))
|
||||
continue;
|
||||
|
||||
|
@ -1027,10 +1040,35 @@ bool X64CPU::IsObjectAccessBreak(uint64 address, DbgModuleMemoryCache* memoryCac
|
|||
|
||||
*outObjectPtr = (uint64)regs[regNum];
|
||||
|
||||
return true;
|
||||
return DbgBreakKind_ObjectAccess;
|
||||
}
|
||||
|
||||
return false;
|
||||
// check jno/jnb
|
||||
for (int offset = 3; offset <= 3; offset++)
|
||||
{
|
||||
if (!Decode(address - offset, memoryCache, &inst))
|
||||
continue;
|
||||
|
||||
if (inst.GetLength() != 2)
|
||||
continue;
|
||||
|
||||
const MCInstrDesc &instDesc = mInstrInfo->get(inst.mMCInst.getOpcode());
|
||||
if (!instDesc.isBranch())
|
||||
continue;
|
||||
|
||||
auto immediateType = (instDesc.TSFlags & llvm::X86II::ImmMask);
|
||||
if ((immediateType == llvm::X86II::Imm8PCRel) && (inst.mMCInst.getNumOperands() == 2))
|
||||
{
|
||||
auto immOp = inst.mMCInst.getOperand(1);
|
||||
if (!immOp.isImm())
|
||||
continue;
|
||||
if ((immOp.getImm() != 1) && (immOp.getImm() != 3))
|
||||
continue;
|
||||
return DbgBreakKind_ArithmeticOverflow;
|
||||
}
|
||||
}
|
||||
|
||||
return DbgBreakKind_None;
|
||||
}
|
||||
|
||||
int X64CPU::GetOpcodesForMnemonic(const StringImpl& mnemonic, Array<int>& outOpcodes)
|
||||
|
|
|
@ -508,7 +508,7 @@ public:
|
|||
String InstructionToString(X64Instr* inst, uint64 addr);
|
||||
|
||||
void GetNextPC(uint64 baseAddress, const uint8* dataBase, int dataLength, const uint8* dataPtr, uint32* regs, uint64 nextPCs[2]);
|
||||
bool IsObjectAccessBreak(uint64 address, DbgModuleMemoryCache* memoryCache, int64* regs, int64* outObjectPtr);
|
||||
DbgBreakKind GetDbgBreakKind(uint64 address, DbgModuleMemoryCache* memoryCache, int64* regs, int64* outObjectPtr);
|
||||
|
||||
int GetOpcodesForMnemonic(const StringImpl& mnemonic, Array<int>& outOpcodes);
|
||||
void GetClobbersForMnemonic(const StringImpl& mnemonic, int argCount, Array<int>& outImplicitClobberRegNums, int& outClobberArgCount, bool& outMayClobberMem);
|
||||
|
|
|
@ -575,26 +575,39 @@ String X86CPU::InstructionToString(X86Instr* inst, uint32 addr)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool X86CPU::IsObjectAccessBreak(uint32 address, DbgModuleMemoryCache* memoryCache, int32* regs, int32* outObjectPtr)
|
||||
DbgBreakKind X86CPU::GetDbgBreakKind(uint32 address, DbgModuleMemoryCache* memoryCache, int32* regs, int32* outObjectPtr)
|
||||
{
|
||||
// We've looking for a CMP BYTE PTR [<reg>], -0x80
|
||||
// if <reg> is R12 then encoding takes an extra 2 bytes
|
||||
X86Instr inst;
|
||||
X86Instr inst;
|
||||
for (int checkLen = 5; checkLen >= 3; checkLen--)
|
||||
{
|
||||
{
|
||||
int offset = -3 - checkLen;
|
||||
|
||||
if (!Decode(address + offset, memoryCache, &inst))
|
||||
continue;
|
||||
continue;
|
||||
|
||||
if (inst.GetLength() != checkLen)
|
||||
continue;
|
||||
|
||||
const MCInstrDesc &instDesc = mInstrInfo->get(inst.mMCInst.getOpcode());
|
||||
const MCInstrDesc& instDesc = mInstrInfo->get(inst.mMCInst.getOpcode());
|
||||
if (!instDesc.isCompare())
|
||||
continue;
|
||||
|
||||
auto immediateType = (instDesc.TSFlags & llvm::X86II::ImmMask);
|
||||
if ((immediateType == llvm::X86II::Imm8) && (inst.mMCInst.getNumOperands() == 2))
|
||||
{
|
||||
// We're checking for a TEST [<reg>], 1
|
||||
if (inst.mMCInst.getOpcode() != llvm::X86::TEST8ri)
|
||||
continue;
|
||||
auto immOp = inst.mMCInst.getOperand(1);
|
||||
if (!immOp.isImm())
|
||||
continue;
|
||||
if (immOp.getImm() != 1)
|
||||
continue;
|
||||
return DbgBreakKind_ArithmeticOverflow;
|
||||
}
|
||||
|
||||
if ((immediateType == 0) || (inst.mMCInst.getNumOperands() < 6))
|
||||
continue;
|
||||
|
||||
|
@ -617,10 +630,35 @@ bool X86CPU::IsObjectAccessBreak(uint32 address, DbgModuleMemoryCache* memoryCac
|
|||
|
||||
*outObjectPtr = (uint64)regs[regNum];
|
||||
|
||||
return true;
|
||||
return DbgBreakKind_ObjectAccess;
|
||||
}
|
||||
|
||||
return false;
|
||||
// check jno/jnb
|
||||
for (int offset = 3; offset <= 3; offset++)
|
||||
{
|
||||
if (!Decode(address - offset, memoryCache, &inst))
|
||||
continue;
|
||||
|
||||
if (inst.GetLength() != 2)
|
||||
continue;
|
||||
|
||||
const MCInstrDesc& instDesc = mInstrInfo->get(inst.mMCInst.getOpcode());
|
||||
if (!instDesc.isBranch())
|
||||
continue;
|
||||
|
||||
auto immediateType = (instDesc.TSFlags & llvm::X86II::ImmMask);
|
||||
if ((immediateType == llvm::X86II::Imm8PCRel) && (inst.mMCInst.getNumOperands() == 2))
|
||||
{
|
||||
auto immOp = inst.mMCInst.getOperand(1);
|
||||
if (!immOp.isImm())
|
||||
continue;
|
||||
if ((immOp.getImm() != 1) && (immOp.getImm() != 3))
|
||||
continue;
|
||||
return DbgBreakKind_ArithmeticOverflow;
|
||||
}
|
||||
}
|
||||
|
||||
return DbgBreakKind_None;
|
||||
}
|
||||
|
||||
int X86CPU::GetOpcodesForMnemonic(const StringImpl& mnemonic, Array<int>& outOpcodes)
|
||||
|
|
|
@ -344,7 +344,7 @@ public:
|
|||
String InstructionToString(X86Instr* inst, uint32 addr);
|
||||
|
||||
void GetNextPC(uint32 baseAddress, const uint8* dataBase, int dataLength, const uint8* dataPtr, uint32* regs, uint32 nextPCs[2]);
|
||||
bool IsObjectAccessBreak(uint32 address, DbgModuleMemoryCache* memoryCache, int32* regs, int32* outObjectPtr);
|
||||
DbgBreakKind GetDbgBreakKind(uint32 address, DbgModuleMemoryCache* memoryCache, int32* regs, int32* outObjectPtr);
|
||||
|
||||
int GetOpcodesForMnemonic(const StringImpl& mnemonic, Array<int>& outOpcodes);
|
||||
void GetClobbersForMnemonic(const StringImpl& mnemonic, int argCount, Array<int>& outImplicitClobberRegNums, int& outClobberArgCount, bool& outMayClobberMem);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue