private static bool TryDecodePseudoFieldData( ClrFieldDefinition pseudoField, IType elementType, out IReadOnlyList <Constant> data) { var init = pseudoField.Definition.InitialValue; var intSpec = elementType.GetIntegerSpecOrNull(); if (intSpec != null && intSpec.Size % 8 == 0) { int bytesPerInt = intSpec.Size / 8; int intCount = init.Length / bytesPerInt; var results = new Constant[intCount]; for (int i = 0; i < intCount; i++) { var value = new IntegerConstant(0, intSpec); for (int j = bytesPerInt - 1; j >= 0; j--) { value = value.ShiftLeft(8).Add(new IntegerConstant(init[i * bytesPerInt + j], intSpec)); } results[i] = value.Normalized; } data = results; return(true); } else { data = null; return(false); } }
public override BlockFlow Emit( FlowGraphBuilder graph, ValueTag value) { // Create the following blocks: // // bitswitch.entry(): // minvalue = const <MinValue> // switchval.adjusted = switchval - minvalue // switchval.unsigned = (uintX)switchval.adjusted // valrange = const <ValueRange> // switch (switchval.unsigned > valrange) // 0 -> bitswitch.header() // default -> <defaultBranch> // // bitswitch.header(): // one = const 1 // shifted = one << switchval.unsigned // bitmask1 = const <bitmask1> // switch (shifted & bitmask1) // 0 -> bitswitch.case2() // default -> <case1Branch> // // bitswitch.case2(): // bitmask2 = const <bitmask2> // switch (shifted & bitmask1) // 0 -> bitswitch.case3() // default -> <case2Branch> // // ... var entryBlock = graph.AddBasicBlock("bitswitch.entry"); var headerBlock = graph.AddBasicBlock("bitswitch.header"); var valueType = graph.GetValueType(value); var valueSpec = valueType.GetIntegerSpecOrNull(); var defaultBranch = Flow.DefaultBranch; // Subtract the min value from the switch value if necessary. if (!MinValue.IsZero) { value = entryBlock.AppendInstruction( Instruction.CreateBinaryArithmeticIntrinsic( ArithmeticIntrinsics.Operators.Subtract, false, valueType, value, entryBlock.AppendInstruction( Instruction.CreateConstant(MinValue, valueType), "minvalue")), "switchval.adjusted"); } // Make the switch value unsigned if it wasn't already. if (valueSpec.IsSigned) { var uintType = TypeEnvironment.MakeUnsignedIntegerType(valueSpec.Size); value = entryBlock.AppendInstruction( Instruction.CreateConvertIntrinsic( false, uintType, valueType, value), "switchval.unsigned"); valueType = uintType; valueSpec = uintType.GetIntegerSpecOrNull(); } // Check that the value is within range. entryBlock.Flow = SwitchFlow.CreateIfElse( Instruction.CreateRelationalIntrinsic( ArithmeticIntrinsics.Operators.IsGreaterThan, TypeEnvironment.Boolean, valueType, value, entryBlock.AppendInstruction( Instruction.CreateConstant( ValueRange.CastSignedness(false), valueType), "valrange")), defaultBranch, new Branch(headerBlock)); // Pick an appropriate type for the bitmasks. var bitmaskType = valueType; if (valueSpec.Size < 32) { bitmaskType = TypeEnvironment.UInt32; } if (ValueRange.IsGreaterThan(new IntegerConstant(valueSpec.Size, ValueRange.Spec))) { bitmaskType = TypeEnvironment.UInt64; } // Set up first part of the header block. if (bitmaskType != valueType) { valueSpec = bitmaskType.GetIntegerSpecOrNull(); } var zero = headerBlock.AppendInstruction( Instruction.CreateConstant( new IntegerConstant(0, valueSpec), valueType), "zero"); var one = headerBlock.AppendInstruction( Instruction.CreateConstant( new IntegerConstant(1, valueSpec), valueType), "one"); value = headerBlock.AppendInstruction( Instruction.CreateArithmeticIntrinsic( ArithmeticIntrinsics.Operators.LeftShift, false, bitmaskType, new[] { bitmaskType, valueType }, new[] { one, value }), "shifted"); valueType = bitmaskType; // Start emitting cases. var caseBlock = headerBlock; var nextCase = graph.AddBasicBlock("bitswitch.case1"); for (int i = 0; i < Flow.Cases.Count; i++) { // Construct a mask for the case. var switchCase = Flow.Cases[i]; var oneConstant = new IntegerConstant(1, valueSpec); var mask = new IntegerConstant(0, valueSpec); foreach (var pattern in switchCase.Values) { mask = mask.BitwiseOr(oneConstant.ShiftLeft(((IntegerConstant)pattern).Subtract(MinValue))); } // Switch on the bitwise 'and' of the mask and // the shifted value. caseBlock.Flow = SwitchFlow.CreateIfElse( Instruction.CreateBinaryArithmeticIntrinsic( ArithmeticIntrinsics.Operators.And, false, valueType, value, caseBlock.AppendInstruction( Instruction.CreateConstant(mask, valueType), "bitmask" + i)), switchCase.Branch, new Branch(nextCase)); caseBlock = nextCase; nextCase = graph.AddBasicBlock("bitswitch.case" + (i + 2)); } // Jump to the default branch if nothing matches. caseBlock.Flow = new JumpFlow(defaultBranch); // Jump to the header block and let it do all of the heavy // lifting. return(new JumpFlow(entryBlock)); }