|
3 | 3 |
|
4 | 4 | using System; |
5 | 5 | using System.Collections.Generic; |
| 6 | +using System.ComponentModel; |
6 | 7 | using System.Diagnostics; |
7 | 8 | using System.IO; |
8 | 9 | using System.Linq; |
@@ -4150,14 +4151,135 @@ private void ImportCompareOperation(ILOpcode opcode) |
4150 | 4151 |
|
4151 | 4152 | private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool unsigned) |
4152 | 4153 | { |
4153 | | - //TODO checkOverflow |
| 4154 | + //TODO checkOverflow - r_un & r_4, i & i_un |
4154 | 4155 | StackEntry value = _stack.Pop(); |
4155 | 4156 | TypeDesc destType = GetWellKnownType(wellKnownType); |
4156 | 4157 |
|
4157 | 4158 | // Load the value and then convert it instead of using ValueAsType to avoid loading the incorrect size |
4158 | 4159 | LLVMValueRef loadedValue = value.ValueAsType(value.Type, _builder); |
4159 | | - LLVMValueRef converted = CastIfNecessary(loadedValue, GetLLVMTypeForTypeDesc(destType), value.Name(), wellKnownType == WellKnownType.UInt64 /* unsigned is always false, so check for the type explicitly */); |
4160 | | - PushExpression(GetStackValueKind(destType), "conv", converted, destType); |
| 4160 | + |
| 4161 | + ExpressionEntry expressionEntry; |
| 4162 | + if (checkOverflow) |
| 4163 | + { |
| 4164 | + Debug.Assert(destType is EcmaType); |
| 4165 | + if (IsLlvmReal(loadedValue.TypeOf)) |
| 4166 | + { |
| 4167 | + expressionEntry = BuildConvOverflowFromReal(value, loadedValue, (EcmaType)destType, wellKnownType, unsigned, value.Type); |
| 4168 | + } |
| 4169 | + else |
| 4170 | + { |
| 4171 | + expressionEntry = BuildConvOverflow(value.Name(), loadedValue, (EcmaType)destType, wellKnownType, unsigned, value.Type); |
| 4172 | + } |
| 4173 | + } |
| 4174 | + else |
| 4175 | + { |
| 4176 | + LLVMValueRef converted = CastIfNecessary(loadedValue, GetLLVMTypeForTypeDesc(destType), value.Name(), wellKnownType == WellKnownType.UInt64 /* unsigned is always false, so check for the type explicitly */); |
| 4177 | + expressionEntry = new ExpressionEntry(GetStackValueKind(destType), "conv", converted, destType); |
| 4178 | + } |
| 4179 | + _stack.Push(expressionEntry); |
| 4180 | + } |
| 4181 | + |
| 4182 | + private bool IsLlvmReal(LLVMTypeRef llvmTypeRef) |
| 4183 | + { |
| 4184 | + return llvmTypeRef == LLVMTypeRef.Float || llvmTypeRef == LLVMTypeRef.Double; |
| 4185 | + } |
| 4186 | + |
| 4187 | + ExpressionEntry BuildConvOverflowFromReal(StackEntry value, LLVMValueRef loadedValue, EcmaType destType, WellKnownType destWellKnownType, bool unsigned, TypeDesc sourceType) |
| 4188 | + { |
| 4189 | + //TODO: single overflow checks extend to doubles - this could be more efficient |
| 4190 | + if (value.Type == GetWellKnownType(WellKnownType.Single)) |
| 4191 | + { |
| 4192 | + value = new ExpressionEntry(StackValueKind.Float, "dbl", _builder.BuildFPExt(loadedValue, LLVMTypeRef.Double), GetWellKnownType(WellKnownType.Double)); |
| 4193 | + } |
| 4194 | + switch (destWellKnownType) |
| 4195 | + { |
| 4196 | + case WellKnownType.Byte: |
| 4197 | + case WellKnownType.SByte: |
| 4198 | + case WellKnownType.Int16: |
| 4199 | + case WellKnownType.UInt16: |
| 4200 | + var intExpression = CallRuntime("Internal.Runtime.CompilerHelpers", _method.Context, "MathHelpers", "Dbl2IntOvf", new[] {value}); |
| 4201 | + return BuildConvOverflow(value.Name(), intExpression.ValueForStackKind(StackValueKind.Int32, _builder, false), destType, destWellKnownType, unsigned, sourceType); |
| 4202 | + case WellKnownType.Int32: |
| 4203 | + return CallRuntime("Internal.Runtime.CompilerHelpers", _method.Context, "MathHelpers", "Dbl2IntOvf", new[] { value }); |
| 4204 | + case WellKnownType.UInt32: |
| 4205 | + case WellKnownType.UIntPtr: // TODO : 64bit. |
| 4206 | + return CallRuntime("Internal.Runtime.CompilerHelpers", _method.Context, "MathHelpers", "Dbl2UIntOvf", new[] { value }); |
| 4207 | + case WellKnownType.Int64: |
| 4208 | + return CallRuntime("Internal.Runtime.CompilerHelpers", _method.Context, "MathHelpers", "Dbl2LngOvf", new[] { value }); |
| 4209 | + case WellKnownType.UInt64: |
| 4210 | + return CallRuntime("Internal.Runtime.CompilerHelpers", _method.Context, "MathHelpers", "Dbl2ULngOvf", new[] { value }); |
| 4211 | + default: |
| 4212 | + throw new InvalidProgramException("Unsupported destination for singled/double overflow check"); |
| 4213 | + } |
| 4214 | + } |
| 4215 | + |
| 4216 | + ExpressionEntry BuildConvOverflow(string name, LLVMValueRef loadedValue, EcmaType destType, WellKnownType destWellKnownType, bool unsigned, TypeDesc sourceType) |
| 4217 | + { |
| 4218 | + ulong maxValue = 0; |
| 4219 | + long minValue = 0; |
| 4220 | + switch (destWellKnownType) |
| 4221 | + { |
| 4222 | + case WellKnownType.Byte: |
| 4223 | + maxValue = byte.MaxValue; |
| 4224 | + break; |
| 4225 | + case WellKnownType.SByte: |
| 4226 | + maxValue = (ulong)sbyte.MaxValue; |
| 4227 | + minValue = sbyte.MinValue; |
| 4228 | + break; |
| 4229 | + case WellKnownType.UInt16: |
| 4230 | + maxValue = ushort.MaxValue; |
| 4231 | + break; |
| 4232 | + case WellKnownType.Int16: |
| 4233 | + maxValue = (ulong)short.MaxValue; |
| 4234 | + minValue = short.MinValue; |
| 4235 | + break; |
| 4236 | + case WellKnownType.UInt32: |
| 4237 | + case WellKnownType.UIntPtr: // TODO : 64bit. |
| 4238 | + maxValue = uint.MaxValue; |
| 4239 | + break; |
| 4240 | + case WellKnownType.Int32: |
| 4241 | + maxValue = int.MaxValue; |
| 4242 | + minValue = int.MinValue; |
| 4243 | + break; |
| 4244 | + case WellKnownType.UInt64: |
| 4245 | + maxValue = ulong.MaxValue; |
| 4246 | + break; |
| 4247 | + case WellKnownType.Int64: |
| 4248 | + maxValue = long.MaxValue; |
| 4249 | + minValue = long.MinValue; |
| 4250 | + break; |
| 4251 | + } |
| 4252 | + BuildConvOverflowCheck(loadedValue, unsigned, maxValue, minValue, sourceType, destType); |
| 4253 | + LLVMValueRef converted = CastIfNecessary(loadedValue, GetLLVMTypeForTypeDesc(destType), name, unsigned); |
| 4254 | + return new ExpressionEntry(GetStackValueKind(destType), "conv", converted, destType); |
| 4255 | + } |
| 4256 | + |
| 4257 | + private void BuildConvOverflowCheck(LLVMValueRef loadedValue, bool unsigned, ulong maxValue, long minValue, TypeDesc sourceType, EcmaType destType) |
| 4258 | + { |
| 4259 | + var maxDiff = LLVMValueRef.CreateConstInt(loadedValue.TypeOf, maxValue - (ulong)minValue); |
| 4260 | + |
| 4261 | + LLVMBasicBlockRef overflowBlock = _currentFunclet.AppendBasicBlock("ovf"); |
| 4262 | + LLVMBasicBlockRef noOverflowBlock = _currentFunclet.AppendBasicBlock("no_ovf"); |
| 4263 | + LLVMValueRef cmp; |
| 4264 | + //special case same width signed -> unsigned, can just check for negative values |
| 4265 | + if (unsigned && (loadedValue.TypeOf.IntWidth >> 3) == destType.InstanceFieldSize.AsInt && |
| 4266 | + (sourceType == GetWellKnownType(WellKnownType.Int16) |
| 4267 | + || sourceType == GetWellKnownType(WellKnownType.Int32) |
| 4268 | + || sourceType == GetWellKnownType(WellKnownType.Int64))) |
| 4269 | + { |
| 4270 | + cmp = _builder.BuildICmp(LLVMIntPredicate.LLVMIntSLT, loadedValue, LLVMValueRef.CreateConstInt(loadedValue.TypeOf, 0)); |
| 4271 | + } |
| 4272 | + else |
| 4273 | + { |
| 4274 | + var valueDiff = _builder.BuildSub(loadedValue, LLVMValueRef.CreateConstInt(loadedValue.TypeOf, (ulong)minValue)); |
| 4275 | + cmp = _builder.BuildICmp(LLVMIntPredicate.LLVMIntUGT, valueDiff, maxDiff); |
| 4276 | + } |
| 4277 | + _builder.BuildCondBr(cmp, overflowBlock, noOverflowBlock); |
| 4278 | + |
| 4279 | + _builder.PositionAtEnd(overflowBlock); |
| 4280 | + CallOrInvokeThrowException(_builder, "ThrowHelpers", "ThrowOverflowException"); |
| 4281 | + _builder.PositionAtEnd(noOverflowBlock); |
| 4282 | + AddInternalBasicBlock(noOverflowBlock); |
4161 | 4283 | } |
4162 | 4284 |
|
4163 | 4285 | private void ImportUnaryOperation(ILOpcode opCode) |
|
0 commit comments