Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
92543440
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
92543440
编写于
7月 13, 2016
作者:
N
Neal Gafter
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Reorganize lowering for switch on float/double/decimal as recommended in code review.
上级
393f4521
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
89 addition
and
72 deletion
+89
-72
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs
...ing/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs
+89
-72
未找到文件。
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs
浏览文件 @
92543440
...
...
@@ -360,17 +360,29 @@ private void LowerBasicSwitch(DecisionTree.ByValue byValue)
}
var
rewrittenSections
=
switchSections
.
ToImmutableAndFree
();
MethodSymbol
stringEquality
=
null
;
switch
(
byValue
.
Type
.
SpecialType
)
if
(
underlyingSwitchType
.
SpecialType
==
SpecialType
.
System_String
)
{
case
SpecialType
.
System_String
:
{
LocalRewriter
.
EnsureStringHashFunction
(
rewrittenSections
,
_factory
.
Syntax
);
stringEquality
=
LocalRewriter
.
GetSpecialTypeMethod
(
_factory
.
Syntax
,
SpecialMember
.
System_String__op_Equality
);
goto
case
SpecialType
.
System_UInt32
;
}
LocalRewriter
.
EnsureStringHashFunction
(
rewrittenSections
,
_factory
.
Syntax
);
stringEquality
=
LocalRewriter
.
GetSpecialTypeMethod
(
_factory
.
Syntax
,
SpecialMember
.
System_String__op_Equality
);
}
// The BoundSwitchStatement requires a constant target when there are no sections, so we accomodate that here.
var
constantTarget
=
rewrittenSections
.
IsEmpty
?
noValueMatches
:
null
;
var
switchStatement
=
new
BoundSwitchStatement
(
_factory
.
Syntax
,
null
,
_factory
.
Convert
(
underlyingSwitchType
,
byValue
.
Expression
),
constantTarget
,
ImmutableArray
<
LocalSymbol
>.
Empty
,
ImmutableArray
<
LocalFunctionSymbol
>.
Empty
,
rewrittenSections
,
noValueMatches
,
stringEquality
);
// The bound switch statement implicitly defines the label noValueMatches at the end, so we do not add it explicitly.
switch
(
underlyingSwitchType
.
SpecialType
)
{
case
SpecialType
.
System_Boolean
:
// boolean switch is handled in LowerBooleanSwitch, not here.
throw
ExceptionUtilities
.
Unreachable
;
case
SpecialType
.
System_String
:
case
SpecialType
.
System_Byte
:
case
SpecialType
.
System_Char
:
case
SpecialType
.
System_Int16
:
...
...
@@ -381,76 +393,16 @@ private void LowerBasicSwitch(DecisionTree.ByValue byValue)
case
SpecialType
.
System_UInt32
:
case
SpecialType
.
System_UInt64
:
{
// Emit requires a constant target when there are no sections, so we accomodate that here.
// CONSIDER: can we get better code generated by giving a constant target more often here,
// e.g. when the switch expression is a constant?
var
constantTarget
=
rewrittenSections
.
IsEmpty
?
noValueMatches
:
null
;
var
switchStatement
=
new
BoundSwitchStatement
(
_factory
.
Syntax
,
null
,
_factory
.
Convert
(
underlyingSwitchType
,
byValue
.
Expression
),
constantTarget
,
ImmutableArray
<
LocalSymbol
>.
Empty
,
ImmutableArray
<
LocalFunctionSymbol
>.
Empty
,
rewrittenSections
,
noValueMatches
,
stringEquality
);
// emit knows how to efficiently generate code for these kinds of switches.
_loweredDecisionTree
.
Add
(
switchStatement
);
// The bound switch statement implicitly defines the label noValueMatches at the end, so we do not add it explicitly.
break
;
}
default
:
{
if
(
byValue
.
Type
.
TypeKind
==
TypeKind
.
Enum
)
{
goto
case
SpecialType
.
System_Int32
;
}
// Here we handle "other" types, such as float, double, and decimal.
// We compare the constant values using value.Equals(input), using ordinary
// overload resolution. Note that we cannot and do not rely on switching
// on the hash code, as it may not be consistent with the behavior of Equals;
// see https://github.com/dotnet/coreclr/issues/6237. Also, the hash code is
// not guaranteed to be the same on the compilation platform as the runtime
// platform.
// CONSIDER: can we improve the quality of the code using comparisons, like
// we do for other numeric types, by generating a series of tests
// that use divide-and-conquer to efficiently find a matching value?
// If so, we should use the BoundSwitchStatement and do that in emit.
LabelSymbol
nextLabel
=
null
;
foreach
(
var
section
in
rewrittenSections
)
{
foreach
(
var
boundSwitchLabel
in
section
.
SwitchLabels
)
{
if
(
nextLabel
!=
null
)
{
_loweredDecisionTree
.
Add
(
_factory
.
Label
(
nextLabel
));
}
nextLabel
=
_factory
.
GenerateLabel
(
"failcase+"
+
section
.
SwitchLabels
[
0
].
ConstantValueOpt
.
Value
);
Debug
.
Assert
(
boundSwitchLabel
.
ConstantValueOpt
!=
null
);
// generate (if (value.Equals(input)) goto label;
var
literal
=
LocalRewriter
.
MakeLiteral
(
_factory
.
Syntax
,
boundSwitchLabel
.
ConstantValueOpt
,
byValue
.
Type
);
var
condition
=
_factory
.
InstanceCall
(
literal
,
"Equals"
,
byValue
.
Expression
);
if
(!
condition
.
HasErrors
&&
condition
.
Type
.
SpecialType
!=
SpecialType
.
System_Boolean
)
{
var
call
=
(
BoundCall
)
condition
;
// '{1} {0}' has the wrong return type
_factory
.
Diagnostics
.
Add
(
ErrorCode
.
ERR_BadRetType
,
boundSwitchLabel
.
Syntax
.
GetLocation
(),
call
.
Method
,
call
.
Type
);
}
_loweredDecisionTree
.
Add
(
_factory
.
ConditionalGoto
(
condition
,
boundSwitchLabel
.
Label
,
true
));
_loweredDecisionTree
.
Add
(
_factory
.
Goto
(
nextLabel
));
}
foreach
(
var
boundSwitchLabel
in
section
.
SwitchLabels
)
{
_loweredDecisionTree
.
Add
(
_factory
.
Label
(
boundSwitchLabel
.
Label
));
}
_loweredDecisionTree
.
Add
(
_factory
.
Block
(
section
.
Statements
));
// this location should not be reachable.
}
Debug
.
Assert
(
nextLabel
!=
null
);
_loweredDecisionTree
.
Add
(
_factory
.
Label
(
nextLabel
));
_loweredDecisionTree
.
Add
(
_factory
.
Label
(
noValueMatches
));
// other types, such as float, double, and decimal, are not currently
// handled by emit and must be lowered here.
_loweredDecisionTree
.
Add
(
LowerNonprimitiveSwitch
(
switchStatement
));
break
;
}
}
...
...
@@ -458,6 +410,71 @@ private void LowerBasicSwitch(DecisionTree.ByValue byValue)
LowerDecisionTree
(
byValue
.
Expression
,
byValue
.
Default
);
}
private
BoundStatement
LowerNonprimitiveSwitch
(
BoundSwitchStatement
switchStatement
)
{
// Here we handle "other" types, such as float, double, and decimal, by
// lowering the BoundSwitchStatement.
// We compare the constant values using value.Equals(input), using ordinary
// overload resolution. Note that we cannot and do not rely on switching
// on the hash code, as it may not be consistent with the behavior of Equals;
// see https://github.com/dotnet/coreclr/issues/6237. Also, the hash code is
// not guaranteed to be the same on the compilation platform as the runtime
// platform.
// CONSIDER: can we improve the quality of the code using comparisons, like
// we do for other numeric types, by generating a series of tests
// that use divide-and-conquer to efficiently find a matching value?
// If so, we should use the BoundSwitchStatement and do that in emit.
// Moreover, we should be able to use `==` rather than `.Equals`
// for cases (such as non-NaN) where we know the result to be the same.
var
rewrittenSections
=
switchStatement
.
SwitchSections
;
var
expression
=
switchStatement
.
Expression
;
var
noValueMatches
=
switchStatement
.
BreakLabel
;
Debug
.
Assert
(
switchStatement
.
LoweredPreambleOpt
==
null
);
Debug
.
Assert
(
switchStatement
.
InnerLocals
.
IsDefaultOrEmpty
);
Debug
.
Assert
(
switchStatement
.
InnerLocalFunctions
.
IsDefaultOrEmpty
);
Debug
.
Assert
(
switchStatement
.
StringEquality
==
null
);
LabelSymbol
nextLabel
=
null
;
var
builder
=
ArrayBuilder
<
BoundStatement
>.
GetInstance
();
foreach
(
var
section
in
rewrittenSections
)
{
foreach
(
var
boundSwitchLabel
in
section
.
SwitchLabels
)
{
if
(
nextLabel
!=
null
)
{
builder
.
Add
(
_factory
.
Label
(
nextLabel
));
}
nextLabel
=
_factory
.
GenerateLabel
(
"failcase+"
+
section
.
SwitchLabels
[
0
].
ConstantValueOpt
.
Value
);
Debug
.
Assert
(
boundSwitchLabel
.
ConstantValueOpt
!=
null
);
// generate (if (value.Equals(input)) goto label;
var
literal
=
LocalRewriter
.
MakeLiteral
(
_factory
.
Syntax
,
boundSwitchLabel
.
ConstantValueOpt
,
expression
.
Type
);
var
condition
=
_factory
.
InstanceCall
(
literal
,
"Equals"
,
expression
);
if
(!
condition
.
HasErrors
&&
condition
.
Type
.
SpecialType
!=
SpecialType
.
System_Boolean
)
{
var
call
=
(
BoundCall
)
condition
;
// '{1} {0}' has the wrong return type
_factory
.
Diagnostics
.
Add
(
ErrorCode
.
ERR_BadRetType
,
boundSwitchLabel
.
Syntax
.
GetLocation
(),
call
.
Method
,
call
.
Type
);
}
builder
.
Add
(
_factory
.
ConditionalGoto
(
condition
,
boundSwitchLabel
.
Label
,
true
));
builder
.
Add
(
_factory
.
Goto
(
nextLabel
));
}
foreach
(
var
boundSwitchLabel
in
section
.
SwitchLabels
)
{
builder
.
Add
(
_factory
.
Label
(
boundSwitchLabel
.
Label
));
}
builder
.
Add
(
_factory
.
Block
(
section
.
Statements
));
// this location should not be reachable.
}
Debug
.
Assert
(
nextLabel
!=
null
);
builder
.
Add
(
_factory
.
Label
(
nextLabel
));
builder
.
Add
(
_factory
.
Label
(
noValueMatches
));
return
_factory
.
Block
(
builder
.
ToImmutableAndFree
());
}
private
void
LowerBooleanSwitch
(
DecisionTree
.
ByValue
byValue
)
{
switch
(
byValue
.
ValueAndDecision
.
Count
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录