Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
b2bb7267
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,发现更多精彩内容 >>
未验证
提交
b2bb7267
编写于
4月 06, 2018
作者:
N
Neal Gafter
提交者:
GitHub
4月 06, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #25992 from alrz/lifted-op
Branchless codegen for lifted nullable operators
上级
b6880c99
36297d47
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
128 addition
and
144 deletion
+128
-144
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
...le/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
+48
-52
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenOptimizedNullableOperators.cs
...rp/Test/Emit/CodeGen/CodeGenOptimizedNullableOperators.cs
+15
-18
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
...arp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
+22
-25
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStructsAndEnum.cs
...mpilers/CSharp/Test/Emit/CodeGen/CodeGenStructsAndEnum.cs
+22
-26
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleEqualityTests.cs
...ers/CSharp/Test/Emit/CodeGen/CodeGenTupleEqualityTests.cs
+21
-23
未找到文件。
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
浏览文件 @
b2bb7267
...
...
@@ -874,25 +874,23 @@ private BoundExpression MakeNullableHasValue(SyntaxNode syntax, BoundExpression
//
// tempx = x;
// tempy = y;
// result = tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ?
// tempx.HasValue == tempy.HasValue :
// false;
// result = (tempx.GetValueOrDefault() == tempy.GetValueOrDefault()) &
// (tempx.HasValue == tempy.HasValue);
//
// and x != y as
//
// tempx = x;
// tempy = y;
// result = tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ?
// tempx.HasValue != tempy.HasValue :
// true;
// result = !((tempx.GetValueOrDefault() == tempy.GetValueOrDefault()) &
// (tempx.HasValue == tempy.HasValue));
//
// Otherwise, we rewrite x OP y as
//
// tempx = x;
// tempy = y;
// result =
tempx.GetValueOrDefault() OP tempy.GetValueOrDefault() ?
//
tempx.HasValue & tempy.HasValue :
//
false;
// result =
(tempx.GetValueOrDefault() OP tempy.GetValueOrDefault()) &
//
(tempx.HasValue & tempy.HasValue);
//
//
// Note that there is no reason to generate "&&" over "&"; the cost of
// the added code for the conditional branch would be about the same as simply doing
...
...
@@ -908,79 +906,77 @@ private BoundExpression MakeNullableHasValue(SyntaxNode syntax, BoundExpression
BoundExpression
xNonNull
=
NullableAlwaysHasValue
(
loweredLeft
);
BoundExpression
yNonNull
=
NullableAlwaysHasValue
(
loweredRight
);
BoundAssignmentOperator
tempAssignmentX
;
BoundLocal
boundTempX
=
_factory
.
StoreToTemp
(
xNonNull
??
loweredLeft
,
out
tempAssignmentX
);
BoundAssignmentOperator
tempAssignmentY
;
BoundLocal
boundTempY
=
_factory
.
StoreToTemp
(
yNonNull
??
loweredRight
,
out
tempAssignmentY
);
BoundLocal
boundTempX
=
_factory
.
StoreToTemp
(
xNonNull
??
loweredLeft
,
out
BoundAssignmentOperator
tempAssignmentX
);
BoundLocal
boundTempY
=
_factory
.
StoreToTemp
(
yNonNull
??
loweredRight
,
out
BoundAssignmentOperator
tempAssignmentY
);
BoundExpression
callX_GetValueOrDefault
=
MakeOptimizedGetValueOrDefault
(
syntax
,
boundTempX
);
BoundExpression
callY_GetValueOrDefault
=
MakeOptimizedGetValueOrDefault
(
syntax
,
boundTempY
);
BoundExpression
callX_HasValue
=
MakeOptimizedHasValue
(
syntax
,
boundTempX
);
BoundExpression
callY_HasValue
=
MakeOptimizedHasValue
(
syntax
,
boundTempY
);
// tempx.GetValueOrDefault() == tempy.GetValueOrDefault()
BinaryOperatorKind
operatorKind
=
kind
.
Operator
();
BinaryOperatorKind
conditionOperator
=
operatorKind
==
BinaryOperatorKind
.
NotEqual
?
BinaryOperatorKind
.
Equal
:
operatorKind
;
TypeSymbol
boolType
=
_compilation
.
GetSpecialType
(
SpecialType
.
System_Boolean
);
BoundExpression
condition
=
MakeBinaryOperator
(
syntax
:
syntax
,
operatorKind
:
conditionOperator
.
WithType
(
kind
.
OperandTypes
()),
loweredLeft
:
callX_GetValueOrDefault
,
loweredRight
:
callY_GetValueOrDefault
,
type
:
boolType
,
method
:
null
);
BinaryOperatorKind
leftOperator
;
BinaryOperatorKind
rightOperator
;
BinaryOperatorKind
consequenceOperator
;
BinaryOperatorKind
operatorKind
=
kind
.
Operator
()
;
switch
(
operatorKind
)
{
case
BinaryOperatorKind
.
Equal
:
consequenceOperator
=
BinaryOperatorKind
.
BoolEqual
;
break
;
case
BinaryOperatorKind
.
NotEqual
:
consequenceOperator
=
BinaryOperatorKind
.
BoolNotEqual
;
leftOperator
=
BinaryOperatorKind
.
Equal
;
rightOperator
=
BinaryOperatorKind
.
BoolEqual
;
break
;
default
:
consequenceOperator
=
BinaryOperatorKind
.
BoolAnd
;
leftOperator
=
operatorKind
;
rightOperator
=
BinaryOperatorKind
.
BoolAnd
;
break
;
}
// tempx.HasValue == tempy.HasValue
BoundExpression
consequence
=
MakeBinaryOperator
(
TypeSymbol
boolType
=
_compilation
.
GetSpecialType
(
SpecialType
.
System_Boolean
);
// (tempx.GetValueOrDefault() OP tempy.GetValueOrDefault())
BoundExpression
leftExpression
=
MakeBinaryOperator
(
syntax
:
syntax
,
operatorKind
:
leftOperator
.
WithType
(
kind
.
OperandTypes
()),
loweredLeft
:
callX_GetValueOrDefault
,
loweredRight
:
callY_GetValueOrDefault
,
type
:
boolType
,
method
:
null
);
// (tempx.HasValue OP tempy.HasValue)
BoundExpression
rightExpression
=
MakeBinaryOperator
(
syntax
:
syntax
,
operatorKind
:
consequence
Operator
,
operatorKind
:
right
Operator
,
loweredLeft
:
callX_HasValue
,
loweredRight
:
callY_HasValue
,
type
:
boolType
,
method
:
null
);
// false
BoundExpression
alternative
=
this
.
MakeBooleanConstant
(
syntax
,
operatorKind
==
BinaryOperatorKind
.
NotEqual
);
// tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ?
// tempx.HasValue == tempy.HasValue :
// false;
BoundExpression
conditionalExpression
=
RewriteConditionalOperator
(
// result = (tempx.GetValueOrDefault() OP tempy.GetValueOrDefault()) &
// (tempx.HasValue OP tempy.HasValue)
BoundExpression
binaryExpression
=
MakeBinaryOperator
(
syntax
:
syntax
,
rewrittenCondition
:
condition
,
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
boolType
,
isRef
:
false
);
operatorKind
:
BinaryOperatorKind
.
BoolAnd
,
loweredLeft
:
leftExpression
,
loweredRight
:
rightExpression
,
type
:
boolType
,
method
:
null
);
// result = !((tempx.GetValueOrDefault() == tempy.GetValueOrDefault()) &
// (tempx.HasValue == tempy.HasValue));
if
(
operatorKind
==
BinaryOperatorKind
.
NotEqual
)
{
binaryExpression
=
_factory
.
Not
(
binaryExpression
);
}
// tempx = x;
// tempy = y;
// result = tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ?
// tempx.HasValue == tempy.HasValue :
// false;
// result = (tempx.GetValueOrDefault() == tempy.GetValueOrDefault()) &
// (tempx.HasValue == tempy.HasValue);
return
new
BoundSequence
(
syntax
:
syntax
,
locals
:
ImmutableArray
.
Create
<
LocalSymbol
>(
boundTempX
.
LocalSymbol
,
boundTempY
.
LocalSymbol
),
sideEffects
:
ImmutableArray
.
Create
<
BoundExpression
>(
tempAssignmentX
,
tempAssignmentY
),
value
:
conditional
Expression
,
value
:
binary
Expression
,
type
:
boolType
);
}
...
...
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenOptimizedNullableOperators.cs
浏览文件 @
b2bb7267
...
...
@@ -1368,10 +1368,10 @@ static bool M5()
"
;
string
expectedOutput
=
""
;
string
expectedIL1
=
@"{
// Code size 3
2 (0x20
)
// Code size 3
1 (0x1f
)
.maxstack 2
.locals init (int? V_0,
int V_1)
int V_1)
IL_0000: call ""int? Program.N1()""
IL_0005: stloc.0
IL_0006: call ""short Program.V2()""
...
...
@@ -1379,23 +1379,22 @@ .maxstack 2
IL_000c: ldloca.s V_0
IL_000e: call ""int int?.GetValueOrDefault()""
IL_0013: ldloc.1
IL_0014: beq.s IL_0018
IL_0016: ldc.i4.0
IL_0017: ret
IL_0018: ldloca.s V_0
IL_001a: call ""bool int?.HasValue.get""
IL_001f: ret
IL_0014: ceq
IL_0016: ldloca.s V_0
IL_0018: call ""bool int?.HasValue.get""
IL_001d: and
IL_001e: ret
}"
;
// TODO: We do a worse job than the native compiler here. Find out why.
string
expectedIL2
=
@"{
// Code size 7
5 (0x4b
)
// Code size 7
2 (0x48
)
.maxstack 2
.locals init (decimal? V_0,
decimal V_1,
int? V_2,
decimal? V_3)
decimal V_1,
int? V_2,
decimal? V_3)
IL_0000: call ""int? Program.N1()""
IL_0005: stloc.2
IL_0006: ldloca.s V_2
...
...
@@ -1416,12 +1415,10 @@ .maxstack 2
IL_0034: call ""decimal decimal?.GetValueOrDefault()""
IL_0039: ldloc.1
IL_003a: call ""bool decimal.op_LessThan(decimal, decimal)""
IL_003f: brtrue.s IL_0043
IL_0041: ldc.i4.0
IL_0042: ret
IL_0043: ldloca.s V_0
IL_0045: call ""bool decimal?.HasValue.get""
IL_004a: ret
IL_003f: ldloca.s V_0
IL_0041: call ""bool decimal?.HasValue.get""
IL_0046: and
IL_0047: ret
}"
;
string
expectedIL3
=
@"{
// Code size 37 (0x25)
...
...
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
浏览文件 @
b2bb7267
...
...
@@ -5966,7 +5966,7 @@ .maxstack 2
IL_000f: ret
}"
).
VerifyIL
(
"C.HasLengthChecked"
,
@"
{
// Code size 4
9 (0x31
)
// Code size 4
8 (0x30
)
.maxstack 2
.locals init (int? V_0,
int V_1,
...
...
@@ -5987,12 +5987,11 @@ .maxstack 2
IL_001d: ldloca.s V_0
IL_001f: call ""int int?.GetValueOrDefault()""
IL_0024: ldloc.1
IL_0025: beq.s IL_0029
IL_0027: ldc.i4.0
IL_0028: ret
IL_0029: ldloca.s V_0
IL_002b: call ""bool int?.HasValue.get""
IL_0030: ret
IL_0025: ceq
IL_0027: ldloca.s V_0
IL_0029: call ""bool int?.HasValue.get""
IL_002e: and
IL_002f: ret
}"
);
}
...
...
@@ -6103,7 +6102,7 @@ static bool NotHasLength(string s, int? len)
verifier
.
VerifyIL
(
"C.NotHasLength"
,
@"
{
// Code size 4
3 (0x2b
)
// Code size 4
2 (0x2a
)
.maxstack 2
.locals init (int? V_0)
IL_0000: ldarg.0
...
...
@@ -6119,14 +6118,13 @@ .locals init (int? V_0)
IL_0014: stloc.0
IL_0015: ldloca.s V_0
IL_0017: call ""int int?.GetValueOrDefault()""
IL_001c: beq.s IL_0020
IL_001e: ldc.i4.1
IL_001f: ret
IL_0020: ldloca.s V_0
IL_0022: call ""bool int?.HasValue.get""
IL_0027: ldc.i4.0
IL_0028: ceq
IL_002a: ret
IL_001c: ceq
IL_001e: ldloca.s V_0
IL_0020: call ""bool int?.HasValue.get""
IL_0025: and
IL_0026: ldc.i4.0
IL_0027: ceq
IL_0029: ret
}"
);
}
...
...
@@ -6816,7 +6814,7 @@ static bool NotHasLength(int? s, int? len)
verifier
.
VerifyIL
(
"C.NotHasLength"
,
@"
{
// Code size 5
8 (0x3a
)
// Code size 5
7 (0x39
)
.maxstack 2
.locals init (int? V_0,
int V_1)
...
...
@@ -6837,14 +6835,13 @@ .maxstack 2
IL_0023: stloc.0
IL_0024: ldloca.s V_0
IL_0026: call ""int int?.GetValueOrDefault()""
IL_002b: beq.s IL_002f
IL_002d: ldc.i4.1
IL_002e: ret
IL_002f: ldloca.s V_0
IL_0031: call ""bool int?.HasValue.get""
IL_0036: ldc.i4.0
IL_0037: ceq
IL_0039: ret
IL_002b: ceq
IL_002d: ldloca.s V_0
IL_002f: call ""bool int?.HasValue.get""
IL_0034: and
IL_0035: ldc.i4.0
IL_0036: ceq
IL_0038: ret
}"
);
}
...
...
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStructsAndEnum.cs
浏览文件 @
b2bb7267
...
...
@@ -2266,7 +2266,7 @@ public static void Eval(object obj1, object obj2)
compilation
.
VerifyIL
(
"NullableTest.EqualEqual"
,
@"
{
// Code size 1
20 (0x78
)
// Code size 1
12 (0x70
)
.maxstack 2
.locals init (decimal? V_0)
IL_0000: ldc.i4.0
...
...
@@ -2280,31 +2280,27 @@ .locals init (decimal? V_0)
IL_001c: ldloca.s V_0
IL_001e: call ""decimal decimal?.GetValueOrDefault()""
IL_0023: call ""bool decimal.op_Equality(decimal, decimal)""
IL_0028: brtrue.s IL_002d
IL_002a: ldc.i4.0
IL_002b: br.s IL_0034
IL_002d: ldloca.s V_0
IL_002f: call ""bool decimal?.HasValue.get""
IL_0034: box ""bool""
IL_0039: ldc.i4.0
IL_003a: box ""bool""
IL_003f: call ""void Test.Eval(object, object)""
IL_0044: ldsfld ""decimal decimal.Zero""
IL_0049: ldsfld ""decimal? NullableTest.NULL""
IL_004e: stloc.0
IL_004f: ldloca.s V_0
IL_0051: call ""decimal decimal?.GetValueOrDefault()""
IL_0056: call ""bool decimal.op_Equality(decimal, decimal)""
IL_005b: brtrue.s IL_0060
IL_005d: ldc.i4.0
IL_005e: br.s IL_0067
IL_0060: ldloca.s V_0
IL_0062: call ""bool decimal?.HasValue.get""
IL_0067: box ""bool""
IL_006c: ldc.i4.0
IL_006d: box ""bool""
IL_0072: call ""void Test.Eval(object, object)""
IL_0077: ret
IL_0028: ldloca.s V_0
IL_002a: call ""bool decimal?.HasValue.get""
IL_002f: and
IL_0030: box ""bool""
IL_0035: ldc.i4.0
IL_0036: box ""bool""
IL_003b: call ""void Test.Eval(object, object)""
IL_0040: ldsfld ""decimal decimal.Zero""
IL_0045: ldsfld ""decimal? NullableTest.NULL""
IL_004a: stloc.0
IL_004b: ldloca.s V_0
IL_004d: call ""decimal decimal?.GetValueOrDefault()""
IL_0052: call ""bool decimal.op_Equality(decimal, decimal)""
IL_0057: ldloca.s V_0
IL_0059: call ""bool decimal?.HasValue.get""
IL_005e: and
IL_005f: box ""bool""
IL_0064: ldc.i4.0
IL_0065: box ""bool""
IL_006a: call ""void Test.Eval(object, object)""
IL_006f: ret
}
"
);
}
...
...
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleEqualityTests.cs
浏览文件 @
b2bb7267
...
...
@@ -536,7 +536,7 @@ static bool M((int?, bool?) t1)
comp
.
VerifyDiagnostics
();
comp
.
VerifyIL
(
"C.M"
,
@"{
// Code size 6
6 (0x42
)
// Code size 6
3 (0x3f
)
.maxstack 2
.locals init (System.ValueTuple<int?, bool?> V_0,
int? V_1,
...
...
@@ -553,28 +553,26 @@ .maxstack 2
IL_000b: ldloca.s V_1
IL_000d: call ""int int?.GetValueOrDefault()""
IL_0012: ldloc.2
IL_0013: beq.s IL_0018
IL_0015: ldc.i4.0
IL_0016: br.s IL_001f
IL_0018: ldloca.s V_1
IL_001a: call ""bool int?.HasValue.get""
IL_001f: brfalse.s IL_0040
IL_0021: ldloc.0
IL_0022: ldfld ""bool? System.ValueTuple<int?, bool?>.Item2""
IL_0027: stloc.3
IL_0028: ldc.i4.1
IL_0029: stloc.s V_4
IL_002b: ldloca.s V_3
IL_002d: call ""bool bool?.GetValueOrDefault()""
IL_0032: ldloc.s V_4
IL_0034: beq.s IL_0038
IL_0036: ldc.i4.0
IL_0037: ret
IL_0038: ldloca.s V_3
IL_003a: call ""bool bool?.HasValue.get""
IL_003f: ret
IL_0040: ldc.i4.0
IL_0041: ret
IL_0013: ceq
IL_0015: ldloca.s V_1
IL_0017: call ""bool int?.HasValue.get""
IL_001c: and
IL_001d: brfalse.s IL_003d
IL_001f: ldloc.0
IL_0020: ldfld ""bool? System.ValueTuple<int?, bool?>.Item2""
IL_0025: stloc.3
IL_0026: ldc.i4.1
IL_0027: stloc.s V_4
IL_0029: ldloca.s V_3
IL_002b: call ""bool bool?.GetValueOrDefault()""
IL_0030: ldloc.s V_4
IL_0032: ceq
IL_0034: ldloca.s V_3
IL_0036: call ""bool bool?.HasValue.get""
IL_003b: and
IL_003c: ret
IL_003d: ldc.i4.0
IL_003e: ret
}"
);
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录