Directly convert from an initializer to a value where possible. (#3306)

If the initializing representation is the same as the value
representation, don't materialize a temporary and perform a value
binding. Instead, directly extract the value, using a new
`value_of_initializer` node.

This removes a lot of redundant `alloca`s from our generated LLVM IR.
This commit is contained in:
Richard Smith
2023-10-31 20:59:28 +00:00
committed by GitHub
parent bc8db9406d
commit 428d11323a
32 changed files with 214 additions and 290 deletions
+1
View File
@@ -695,6 +695,7 @@ class TypeCompleter {
case SemIR::TupleValue::Kind:
case SemIR::UnaryOperatorNot::Kind:
case SemIR::ValueAsReference::Kind:
case SemIR::ValueOfInitializer::Kind:
case SemIR::VarStorage::Kind:
CARBON_FATAL() << "Type refers to non-type node " << node;
+23 -4
View File
@@ -563,10 +563,29 @@ static auto PerformBuiltinConversion(Context& context, Parse::Node parse_node,
// If the value is already of the right kind and expression category, there's
// nothing to do. Performing a conversion would decompose and rebuild tuples
// and structs, so it's important that we bail out early in this case.
if (value_type_id == target.type_id &&
IsValidExpressionCategoryForConversionTarget(
SemIR::GetExpressionCategory(sem_ir, value_id), target.kind)) {
return value_id;
if (value_type_id == target.type_id) {
auto value_cat = SemIR::GetExpressionCategory(sem_ir, value_id);
if (IsValidExpressionCategoryForConversionTarget(value_cat, target.kind)) {
return value_id;
}
// If the source is an initializing expression, we may be able to pull a
// value right out of it.
if (value_cat == SemIR::ExpressionCategory::Initializing &&
IsValidExpressionCategoryForConversionTarget(
SemIR::ExpressionCategory::Value, target.kind) &&
SemIR::GetInitializingRepresentation(sem_ir, value_type_id).kind ==
SemIR::InitializingRepresentation::ByCopy) {
auto value_rep = SemIR::GetValueRepresentation(sem_ir, value_type_id);
if (value_rep.kind == SemIR::ValueRepresentation::Copy &&
value_rep.type_id == value_type_id) {
// The initializer produces an object representation by copy, and the
// value representation is a copy of the object representation, so we
// already have a value of the right form.
return context.AddNode(
SemIR::ValueOfInitializer{parse_node, value_type_id, value_id});
}
}
}
// A tuple (T1, T2, ..., Tn) converts to (U1, U2, ..., Un) if each Ti
+3 -5
View File
@@ -50,9 +50,7 @@ fn G() -> i32 {
// CHECK:STDOUT: %.loc12_20.13: init [i32; 3] = array_init %.loc12_20.2, (%.loc12_20.6, %.loc12_20.9, %.loc12_20.12) to %.loc12_20.3
// CHECK:STDOUT: %.loc12_20.14: ref [i32; 3] = temporary %.loc12_20.3, %.loc12_20.13
// CHECK:STDOUT: %.loc12_20.15: [i32; 3] = bind_value %.loc12_20.14
// CHECK:STDOUT: %.loc12_11.1: init i32 = call %F.ref(%.loc12_20.15, %.loc12_23)
// CHECK:STDOUT: %.loc12_11.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc12_11.3: ref i32 = temporary %.loc12_11.2, %.loc12_11.1
// CHECK:STDOUT: %.loc12_11.4: i32 = bind_value %.loc12_11.3
// CHECK:STDOUT: return %.loc12_11.4
// CHECK:STDOUT: %.loc12_11: init i32 = call %F.ref(%.loc12_20.15, %.loc12_23)
// CHECK:STDOUT: %.loc12_25: i32 = value_of_initializer %.loc12_11
// CHECK:STDOUT: return %.loc12_25
// CHECK:STDOUT: }
+3 -5
View File
@@ -60,9 +60,7 @@ fn Run() -> i32 {
// CHECK:STDOUT: %Class.ref: type = name_reference "Class", file.%Class
// CHECK:STDOUT: %F.ref: <function> = name_reference "F", @Class.%F
// CHECK:STDOUT: %.loc22_18: i32 = int_literal 4
// CHECK:STDOUT: %.loc22_17.1: init i32 = call %F.ref(%.loc22_18)
// CHECK:STDOUT: %.loc22_17.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc22_17.3: ref i32 = temporary %.loc22_17.2, %.loc22_17.1
// CHECK:STDOUT: %.loc22_17.4: i32 = bind_value %.loc22_17.3
// CHECK:STDOUT: return %.loc22_17.4
// CHECK:STDOUT: %.loc22_17: init i32 = call %F.ref(%.loc22_18)
// CHECK:STDOUT: %.loc22_20: i32 = value_of_initializer %.loc22_17
// CHECK:STDOUT: return %.loc22_20
// CHECK:STDOUT: }
+18 -30
View File
@@ -86,11 +86,9 @@ fn CallGOnInitializingExpression() -> i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %c.ref: Class = name_reference "c", %c
// CHECK:STDOUT: %.loc21_11: <bound method> = bound_method %c.ref, @Class.%F
// CHECK:STDOUT: %.loc21_13.1: init i32 = call %.loc21_11(%c.ref)
// CHECK:STDOUT: %.loc21_13.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc21_13.3: ref i32 = temporary %.loc21_13.2, %.loc21_13.1
// CHECK:STDOUT: %.loc21_13.4: i32 = bind_value %.loc21_13.3
// CHECK:STDOUT: return %.loc21_13.4
// CHECK:STDOUT: %.loc21_13: init i32 = call %.loc21_11(%c.ref)
// CHECK:STDOUT: %.loc21_15: i32 = value_of_initializer %.loc21_13
// CHECK:STDOUT: return %.loc21_15
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @CallWithAddr() -> i32 {
@@ -101,11 +99,9 @@ fn CallGOnInitializingExpression() -> i32 {
// CHECK:STDOUT: %c.ref: ref Class = name_reference "c", %c
// CHECK:STDOUT: %.loc26_11: <bound method> = bound_method %c.ref, @Class.%G
// CHECK:STDOUT: %.loc26_10: Class* = address_of %c.ref
// CHECK:STDOUT: %.loc26_13.1: init i32 = call %.loc26_11(%.loc26_10)
// CHECK:STDOUT: %.loc26_13.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc26_13.3: ref i32 = temporary %.loc26_13.2, %.loc26_13.1
// CHECK:STDOUT: %.loc26_13.4: i32 = bind_value %.loc26_13.3
// CHECK:STDOUT: return %.loc26_13.4
// CHECK:STDOUT: %.loc26_13: init i32 = call %.loc26_11(%.loc26_10)
// CHECK:STDOUT: %.loc26_15: i32 = value_of_initializer %.loc26_13
// CHECK:STDOUT: return %.loc26_15
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @CallFThroughPointer(%p: Class*) -> i32 {
@@ -114,11 +110,9 @@ fn CallGOnInitializingExpression() -> i32 {
// CHECK:STDOUT: %.loc30_11.1: ref Class = dereference %p.ref
// CHECK:STDOUT: %.loc30_14: <bound method> = bound_method %.loc30_11.1, @Class.%F
// CHECK:STDOUT: %.loc30_11.2: Class = bind_value %.loc30_11.1
// CHECK:STDOUT: %.loc30_16.1: init i32 = call %.loc30_14(%.loc30_11.2)
// CHECK:STDOUT: %.loc30_16.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc30_16.3: ref i32 = temporary %.loc30_16.2, %.loc30_16.1
// CHECK:STDOUT: %.loc30_16.4: i32 = bind_value %.loc30_16.3
// CHECK:STDOUT: return %.loc30_16.4
// CHECK:STDOUT: %.loc30_16: init i32 = call %.loc30_14(%.loc30_11.2)
// CHECK:STDOUT: %.loc30_18: i32 = value_of_initializer %.loc30_16
// CHECK:STDOUT: return %.loc30_18
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @CallGThroughPointer(%p: Class*) -> i32 {
@@ -127,11 +121,9 @@ fn CallGOnInitializingExpression() -> i32 {
// CHECK:STDOUT: %.loc34_11.1: ref Class = dereference %p.ref
// CHECK:STDOUT: %.loc34_14: <bound method> = bound_method %.loc34_11.1, @Class.%G
// CHECK:STDOUT: %.loc34_11.2: Class* = address_of %.loc34_11.1
// CHECK:STDOUT: %.loc34_16.1: init i32 = call %.loc34_14(%.loc34_11.2)
// CHECK:STDOUT: %.loc34_16.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc34_16.3: ref i32 = temporary %.loc34_16.2, %.loc34_16.1
// CHECK:STDOUT: %.loc34_16.4: i32 = bind_value %.loc34_16.3
// CHECK:STDOUT: return %.loc34_16.4
// CHECK:STDOUT: %.loc34_16: init i32 = call %.loc34_14(%.loc34_11.2)
// CHECK:STDOUT: %.loc34_18: i32 = value_of_initializer %.loc34_16
// CHECK:STDOUT: return %.loc34_18
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Make() -> %return: Class;
@@ -144,11 +136,9 @@ fn CallGOnInitializingExpression() -> i32 {
// CHECK:STDOUT: %.loc40_14.3: ref Class = temporary %.loc40_14.1, %.loc40_14.2
// CHECK:STDOUT: %.loc40_16: <bound method> = bound_method %.loc40_14.3, @Class.%F
// CHECK:STDOUT: %.loc40_14.4: Class = bind_value %.loc40_14.3
// CHECK:STDOUT: %.loc40_18.1: init i32 = call %.loc40_16(%.loc40_14.4)
// CHECK:STDOUT: %.loc40_18.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc40_18.3: ref i32 = temporary %.loc40_18.2, %.loc40_18.1
// CHECK:STDOUT: %.loc40_18.4: i32 = bind_value %.loc40_18.3
// CHECK:STDOUT: return %.loc40_18.4
// CHECK:STDOUT: %.loc40_18: init i32 = call %.loc40_16(%.loc40_14.4)
// CHECK:STDOUT: %.loc40_20: i32 = value_of_initializer %.loc40_18
// CHECK:STDOUT: return %.loc40_20
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @CallGOnInitializingExpression() -> i32 {
@@ -159,9 +149,7 @@ fn CallGOnInitializingExpression() -> i32 {
// CHECK:STDOUT: %.loc44_14.3: ref Class = temporary %.loc44_14.1, %.loc44_14.2
// CHECK:STDOUT: %.loc44_16: <bound method> = bound_method %.loc44_14.3, @Class.%G
// CHECK:STDOUT: %.loc44_14.4: Class* = address_of %.loc44_14.3
// CHECK:STDOUT: %.loc44_18.1: init i32 = call %.loc44_16(%.loc44_14.4)
// CHECK:STDOUT: %.loc44_18.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc44_18.3: ref i32 = temporary %.loc44_18.2, %.loc44_18.1
// CHECK:STDOUT: %.loc44_18.4: i32 = bind_value %.loc44_18.3
// CHECK:STDOUT: return %.loc44_18.4
// CHECK:STDOUT: %.loc44_18: init i32 = call %.loc44_16(%.loc44_14.4)
// CHECK:STDOUT: %.loc44_20: i32 = value_of_initializer %.loc44_18
// CHECK:STDOUT: return %.loc44_20
// CHECK:STDOUT: }
+5 -9
View File
@@ -48,16 +48,12 @@ fn Run() -> i32 {
// CHECK:STDOUT: fn @Run() -> i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %F.ref.loc18_10: <function> = name_reference "F", file.%F
// CHECK:STDOUT: %.loc18_11.1: init i32 = call %F.ref.loc18_10()
// CHECK:STDOUT: %.loc18_11: init i32 = call %F.ref.loc18_10()
// CHECK:STDOUT: %Class.ref: type = name_reference "Class", file.%Class
// CHECK:STDOUT: %F.ref.loc18_21: <function> = name_reference "F", @Class.%F
// CHECK:STDOUT: %.loc18_23.1: init i32 = call %F.ref.loc18_21()
// CHECK:STDOUT: %.loc18_11.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc18_11.3: ref i32 = temporary %.loc18_11.2, %.loc18_11.1
// CHECK:STDOUT: %.loc18_11.4: i32 = bind_value %.loc18_11.3
// CHECK:STDOUT: %.loc18_23.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc18_23.3: ref i32 = temporary %.loc18_23.2, %.loc18_23.1
// CHECK:STDOUT: %.loc18_23.4: i32 = bind_value %.loc18_23.3
// CHECK:STDOUT: %.loc18_14: i32 = add %.loc18_11.4, %.loc18_23.4
// CHECK:STDOUT: return %.loc18_14
// CHECK:STDOUT: %.loc18_14.1: i32 = value_of_initializer %.loc18_11
// CHECK:STDOUT: %.loc18_23.2: i32 = value_of_initializer %.loc18_23.1
// CHECK:STDOUT: %.loc18_14.2: i32 = add %.loc18_14.1, %.loc18_23.2
// CHECK:STDOUT: return %.loc18_14.2
// CHECK:STDOUT: }
+3 -5
View File
@@ -45,9 +45,7 @@ fn Class.F[self: Class]() -> i32 {
// CHECK:STDOUT: %.loc16_11.1: ref Class = dereference %.loc16_16.2
// CHECK:STDOUT: %.loc16_19: <bound method> = bound_method %.loc16_11.1, @Class.%F
// CHECK:STDOUT: %.loc16_11.2: Class = bind_value %.loc16_11.1
// CHECK:STDOUT: %.loc16_21.1: init i32 = call %.loc16_19(%.loc16_11.2)
// CHECK:STDOUT: %.loc16_21.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc16_21.3: ref i32 = temporary %.loc16_21.2, %.loc16_21.1
// CHECK:STDOUT: %.loc16_21.4: i32 = bind_value %.loc16_21.3
// CHECK:STDOUT: return %.loc16_21.4
// CHECK:STDOUT: %.loc16_21: init i32 = call %.loc16_19(%.loc16_11.2)
// CHECK:STDOUT: %.loc16_23: i32 = value_of_initializer %.loc16_21
// CHECK:STDOUT: return %.loc16_23
// CHECK:STDOUT: }
+3 -5
View File
@@ -38,9 +38,7 @@ fn Run() -> i32 {
// CHECK:STDOUT: %c: ref Class = bind_name "c", %c.var
// CHECK:STDOUT: %c.ref: ref Class = name_reference "c", %c
// CHECK:STDOUT: %F.ref: <function> = name_reference "F", @Class.%F
// CHECK:STDOUT: %.loc13_13.1: init i32 = call %F.ref()
// CHECK:STDOUT: %.loc13_13.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc13_13.3: ref i32 = temporary %.loc13_13.2, %.loc13_13.1
// CHECK:STDOUT: %.loc13_13.4: i32 = bind_value %.loc13_13.3
// CHECK:STDOUT: return %.loc13_13.4
// CHECK:STDOUT: %.loc13_13: init i32 = call %F.ref()
// CHECK:STDOUT: %.loc13_15: i32 = value_of_initializer %.loc13_13
// CHECK:STDOUT: return %.loc13_15
// CHECK:STDOUT: }
@@ -42,18 +42,14 @@ fn G() -> i32 {
// CHECK:STDOUT: !if.expr.then:
// CHECK:STDOUT: %A.ref: <function> = name_reference "A", file.%A
// CHECK:STDOUT: %.loc11_24.1: init i32 = call %A.ref()
// CHECK:STDOUT: %.loc11_24.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc11_24.3: ref i32 = temporary %.loc11_24.2, %.loc11_24.1
// CHECK:STDOUT: %.loc11_24.4: i32 = bind_value %.loc11_24.3
// CHECK:STDOUT: br !if.expr.result(%.loc11_24.4)
// CHECK:STDOUT: %.loc11_24.2: i32 = value_of_initializer %.loc11_24.1
// CHECK:STDOUT: br !if.expr.result(%.loc11_24.2)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.else:
// CHECK:STDOUT: %B.ref: <function> = name_reference "B", file.%B
// CHECK:STDOUT: %.loc11_33.1: init i32 = call %B.ref()
// CHECK:STDOUT: %.loc11_33.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc11_33.3: ref i32 = temporary %.loc11_33.2, %.loc11_33.1
// CHECK:STDOUT: %.loc11_33.4: i32 = bind_value %.loc11_33.3
// CHECK:STDOUT: br !if.expr.result(%.loc11_33.4)
// CHECK:STDOUT: %.loc11_33: init i32 = call %B.ref()
// CHECK:STDOUT: %.loc11_27: i32 = value_of_initializer %.loc11_33
// CHECK:STDOUT: br !if.expr.result(%.loc11_27)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.result:
// CHECK:STDOUT: %.loc11_10: i32 = block_arg !if.expr.result
@@ -68,18 +64,14 @@ fn G() -> i32 {
// CHECK:STDOUT: !if.expr.then:
// CHECK:STDOUT: %A.ref: <function> = name_reference "A", file.%A
// CHECK:STDOUT: %.loc15_25.1: init i32 = call %A.ref()
// CHECK:STDOUT: %.loc15_25.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc15_25.3: ref i32 = temporary %.loc15_25.2, %.loc15_25.1
// CHECK:STDOUT: %.loc15_25.4: i32 = bind_value %.loc15_25.3
// CHECK:STDOUT: br !if.expr.result(%.loc15_25.4)
// CHECK:STDOUT: %.loc15_25.2: i32 = value_of_initializer %.loc15_25.1
// CHECK:STDOUT: br !if.expr.result(%.loc15_25.2)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.else:
// CHECK:STDOUT: %B.ref: <function> = name_reference "B", file.%B
// CHECK:STDOUT: %.loc15_34.1: init i32 = call %B.ref()
// CHECK:STDOUT: %.loc15_34.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc15_34.3: ref i32 = temporary %.loc15_34.2, %.loc15_34.1
// CHECK:STDOUT: %.loc15_34.4: i32 = bind_value %.loc15_34.3
// CHECK:STDOUT: br !if.expr.result(%.loc15_34.4)
// CHECK:STDOUT: %.loc15_34: init i32 = call %B.ref()
// CHECK:STDOUT: %.loc15_28: i32 = value_of_initializer %.loc15_34
// CHECK:STDOUT: br !if.expr.result(%.loc15_28)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.result:
// CHECK:STDOUT: %.loc15_10: i32 = block_arg !if.expr.result
+5 -9
View File
@@ -37,18 +37,14 @@ fn F(b: bool) -> i32 {
// CHECK:STDOUT: !if.expr.then:
// CHECK:STDOUT: %A.ref: <function> = name_reference "A", file.%A
// CHECK:STDOUT: %.loc11_21.1: init i32 = call %A.ref()
// CHECK:STDOUT: %.loc11_21.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc11_21.3: ref i32 = temporary %.loc11_21.2, %.loc11_21.1
// CHECK:STDOUT: %.loc11_21.4: i32 = bind_value %.loc11_21.3
// CHECK:STDOUT: br !if.expr.result(%.loc11_21.4)
// CHECK:STDOUT: %.loc11_21.2: i32 = value_of_initializer %.loc11_21.1
// CHECK:STDOUT: br !if.expr.result(%.loc11_21.2)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.else:
// CHECK:STDOUT: %B.ref: <function> = name_reference "B", file.%B
// CHECK:STDOUT: %.loc11_30.1: init i32 = call %B.ref()
// CHECK:STDOUT: %.loc11_30.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc11_30.3: ref i32 = temporary %.loc11_30.2, %.loc11_30.1
// CHECK:STDOUT: %.loc11_30.4: i32 = bind_value %.loc11_30.3
// CHECK:STDOUT: br !if.expr.result(%.loc11_30.4)
// CHECK:STDOUT: %.loc11_30: init i32 = call %B.ref()
// CHECK:STDOUT: %.loc11_24: i32 = value_of_initializer %.loc11_30
// CHECK:STDOUT: br !if.expr.result(%.loc11_24)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.result:
// CHECK:STDOUT: %.loc11_10: i32 = block_arg !if.expr.result
+9 -13
View File
@@ -32,22 +32,18 @@ fn And() -> bool {
// CHECK:STDOUT: fn @And() -> bool {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %F.ref: <function> = name_reference "F", file.%F
// CHECK:STDOUT: %.loc11_11.1: init bool = call %F.ref()
// CHECK:STDOUT: %.loc11_11.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc11_11.3: ref bool = temporary %.loc11_11.2, %.loc11_11.1
// CHECK:STDOUT: %.loc11_11.4: bool = bind_value %.loc11_11.3
// CHECK:STDOUT: %.loc11_14.1: bool = bool_literal false
// CHECK:STDOUT: if %.loc11_11.4 br !and.rhs else br !and.result(%.loc11_14.1)
// CHECK:STDOUT: %.loc11_11: init bool = call %F.ref()
// CHECK:STDOUT: %.loc11_14.1: bool = value_of_initializer %.loc11_11
// CHECK:STDOUT: %.loc11_14.2: bool = bool_literal false
// CHECK:STDOUT: if %.loc11_14.1 br !and.rhs else br !and.result(%.loc11_14.2)
// CHECK:STDOUT:
// CHECK:STDOUT: !and.rhs:
// CHECK:STDOUT: %G.ref: <function> = name_reference "G", file.%G
// CHECK:STDOUT: %.loc11_19.1: init bool = call %G.ref()
// CHECK:STDOUT: %.loc11_19.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc11_19.3: ref bool = temporary %.loc11_19.2, %.loc11_19.1
// CHECK:STDOUT: %.loc11_19.4: bool = bind_value %.loc11_19.3
// CHECK:STDOUT: br !and.result(%.loc11_19.4)
// CHECK:STDOUT: %.loc11_19: init bool = call %G.ref()
// CHECK:STDOUT: %.loc11_14.3: bool = value_of_initializer %.loc11_19
// CHECK:STDOUT: br !and.result(%.loc11_14.3)
// CHECK:STDOUT:
// CHECK:STDOUT: !and.result:
// CHECK:STDOUT: %.loc11_14.2: bool = block_arg !and.result
// CHECK:STDOUT: return %.loc11_14.2
// CHECK:STDOUT: %.loc11_14.4: bool = block_arg !and.result
// CHECK:STDOUT: return %.loc11_14.4
// CHECK:STDOUT: }
+10 -14
View File
@@ -32,23 +32,19 @@ fn Or() -> bool {
// CHECK:STDOUT: fn @Or() -> bool {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %F.ref: <function> = name_reference "F", file.%F
// CHECK:STDOUT: %.loc11_11.1: init bool = call %F.ref()
// CHECK:STDOUT: %.loc11_11.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc11_11.3: ref bool = temporary %.loc11_11.2, %.loc11_11.1
// CHECK:STDOUT: %.loc11_11.4: bool = bind_value %.loc11_11.3
// CHECK:STDOUT: %.loc11_14.1: bool = not %.loc11_11.4
// CHECK:STDOUT: %.loc11_14.2: bool = bool_literal true
// CHECK:STDOUT: if %.loc11_14.1 br !or.rhs else br !or.result(%.loc11_14.2)
// CHECK:STDOUT: %.loc11_11: init bool = call %F.ref()
// CHECK:STDOUT: %.loc11_14.1: bool = value_of_initializer %.loc11_11
// CHECK:STDOUT: %.loc11_14.2: bool = not %.loc11_14.1
// CHECK:STDOUT: %.loc11_14.3: bool = bool_literal true
// CHECK:STDOUT: if %.loc11_14.2 br !or.rhs else br !or.result(%.loc11_14.3)
// CHECK:STDOUT:
// CHECK:STDOUT: !or.rhs:
// CHECK:STDOUT: %G.ref: <function> = name_reference "G", file.%G
// CHECK:STDOUT: %.loc11_18.1: init bool = call %G.ref()
// CHECK:STDOUT: %.loc11_18.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc11_18.3: ref bool = temporary %.loc11_18.2, %.loc11_18.1
// CHECK:STDOUT: %.loc11_18.4: bool = bind_value %.loc11_18.3
// CHECK:STDOUT: br !or.result(%.loc11_18.4)
// CHECK:STDOUT: %.loc11_18: init bool = call %G.ref()
// CHECK:STDOUT: %.loc11_14.4: bool = value_of_initializer %.loc11_18
// CHECK:STDOUT: br !or.result(%.loc11_14.4)
// CHECK:STDOUT:
// CHECK:STDOUT: !or.result:
// CHECK:STDOUT: %.loc11_14.3: bool = block_arg !or.result
// CHECK:STDOUT: return %.loc11_14.3
// CHECK:STDOUT: %.loc11_14.5: bool = block_arg !or.result
// CHECK:STDOUT: return %.loc11_14.5
// CHECK:STDOUT: }
+8 -12
View File
@@ -28,21 +28,17 @@ fn F() -> {.a: i32, .b: f64} {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc11_27: type = struct_type {.a: i32, .b: f64}
// CHECK:STDOUT: %MakeF64.ref: <function> = name_reference "MakeF64", file.%MakeF64
// CHECK:STDOUT: %.loc11_44.1: init f64 = call %MakeF64.ref()
// CHECK:STDOUT: %.loc11_44: init f64 = call %MakeF64.ref()
// CHECK:STDOUT: %MakeI32.ref: <function> = name_reference "MakeI32", file.%MakeI32
// CHECK:STDOUT: %.loc11_60.1: init i32 = call %MakeI32.ref()
// CHECK:STDOUT: %.loc11_60: init i32 = call %MakeI32.ref()
// CHECK:STDOUT: %.loc11_62.1: type = struct_type {.b: f64, .a: i32}
// CHECK:STDOUT: %.loc11_62.2: {.b: f64, .a: i32} = struct_literal (%.loc11_44.1, %.loc11_60.1)
// CHECK:STDOUT: %.loc11_60.2: ref i32 = temporary_storage
// CHECK:STDOUT: %.loc11_60.3: ref i32 = temporary %.loc11_60.2, %.loc11_60.1
// CHECK:STDOUT: %.loc11_60.4: i32 = bind_value %.loc11_60.3
// CHECK:STDOUT: %.loc11_44.2: ref f64 = temporary_storage
// CHECK:STDOUT: %.loc11_44.3: ref f64 = temporary %.loc11_44.2, %.loc11_44.1
// CHECK:STDOUT: %.loc11_44.4: f64 = bind_value %.loc11_44.3
// CHECK:STDOUT: %.loc11_62.3: {.a: i32, .b: f64} = struct_value %.loc11_62.2, (%.loc11_60.4, %.loc11_44.4)
// CHECK:STDOUT: %x: {.a: i32, .b: f64} = bind_name "x", %.loc11_62.3
// CHECK:STDOUT: %.loc11_62.2: {.b: f64, .a: i32} = struct_literal (%.loc11_44, %.loc11_60)
// CHECK:STDOUT: %.loc11_62.3: i32 = value_of_initializer %.loc11_60
// CHECK:STDOUT: %.loc11_62.4: f64 = value_of_initializer %.loc11_44
// CHECK:STDOUT: %.loc11_62.5: {.a: i32, .b: f64} = struct_value %.loc11_62.2, (%.loc11_62.3, %.loc11_62.4)
// CHECK:STDOUT: %x: {.a: i32, .b: f64} = bind_name "x", %.loc11_62.5
// CHECK:STDOUT: %.loc12_27: type = struct_type {.b: f64, .a: i32}
// CHECK:STDOUT: %.loc11_62.4: type = ptr_type {.b: f64, .a: i32}
// CHECK:STDOUT: %.loc11_62.6: type = ptr_type {.b: f64, .a: i32}
// CHECK:STDOUT: %x.ref: {.a: i32, .b: f64} = name_reference "x", %x
// CHECK:STDOUT: %.loc12_31.1: f64 = struct_access %x.ref, member1
// CHECK:STDOUT: %.loc12_31.2: i32 = struct_access %x.ref, member0
+24 -40
View File
@@ -60,30 +60,24 @@ fn While() {
// CHECK:STDOUT:
// CHECK:STDOUT: !while.cond.loc17:
// CHECK:STDOUT: %A.ref: <function> = name_reference "A", file.%A
// CHECK:STDOUT: %.loc17_11.1: init bool = call %A.ref()
// CHECK:STDOUT: %.loc17_11.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc17_11.3: ref bool = temporary %.loc17_11.2, %.loc17_11.1
// CHECK:STDOUT: %.loc17_11.4: bool = bind_value %.loc17_11.3
// CHECK:STDOUT: if %.loc17_11.4 br !while.body.loc17 else br !while.done.loc17
// CHECK:STDOUT: %.loc17_11: init bool = call %A.ref()
// CHECK:STDOUT: %.loc17_13: bool = value_of_initializer %.loc17_11
// CHECK:STDOUT: if %.loc17_13 br !while.body.loc17 else br !while.done.loc17
// CHECK:STDOUT:
// CHECK:STDOUT: !while.body.loc17:
// CHECK:STDOUT: %B.ref: <function> = name_reference "B", file.%B
// CHECK:STDOUT: %.loc18_10.1: init bool = call %B.ref()
// CHECK:STDOUT: %.loc18_10.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc18_10.3: ref bool = temporary %.loc18_10.2, %.loc18_10.1
// CHECK:STDOUT: %.loc18_10.4: bool = bind_value %.loc18_10.3
// CHECK:STDOUT: if %.loc18_10.4 br !if.then.loc18 else br !if.else.loc18
// CHECK:STDOUT: %.loc18_10: init bool = call %B.ref()
// CHECK:STDOUT: %.loc18_12: bool = value_of_initializer %.loc18_10
// CHECK:STDOUT: if %.loc18_12 br !if.then.loc18 else br !if.else.loc18
// CHECK:STDOUT:
// CHECK:STDOUT: !if.then.loc18:
// CHECK:STDOUT: br !while.cond.loc17
// CHECK:STDOUT:
// CHECK:STDOUT: !if.else.loc18:
// CHECK:STDOUT: %C.ref: <function> = name_reference "C", file.%C
// CHECK:STDOUT: %.loc19_10.1: init bool = call %C.ref()
// CHECK:STDOUT: %.loc19_10.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc19_10.3: ref bool = temporary %.loc19_10.2, %.loc19_10.1
// CHECK:STDOUT: %.loc19_10.4: bool = bind_value %.loc19_10.3
// CHECK:STDOUT: if %.loc19_10.4 br !if.then.loc19 else br !if.else.loc19
// CHECK:STDOUT: %.loc19_10: init bool = call %C.ref()
// CHECK:STDOUT: %.loc19_12: bool = value_of_initializer %.loc19_10
// CHECK:STDOUT: if %.loc19_12 br !if.then.loc19 else br !if.else.loc19
// CHECK:STDOUT:
// CHECK:STDOUT: !if.then.loc19:
// CHECK:STDOUT: br !while.done.loc17
@@ -93,30 +87,24 @@ fn While() {
// CHECK:STDOUT:
// CHECK:STDOUT: !while.cond.loc20:
// CHECK:STDOUT: %D.ref: <function> = name_reference "D", file.%D
// CHECK:STDOUT: %.loc20_13.1: init bool = call %D.ref()
// CHECK:STDOUT: %.loc20_13.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc20_13.3: ref bool = temporary %.loc20_13.2, %.loc20_13.1
// CHECK:STDOUT: %.loc20_13.4: bool = bind_value %.loc20_13.3
// CHECK:STDOUT: if %.loc20_13.4 br !while.body.loc20 else br !while.done.loc20
// CHECK:STDOUT: %.loc20_13: init bool = call %D.ref()
// CHECK:STDOUT: %.loc20_15: bool = value_of_initializer %.loc20_13
// CHECK:STDOUT: if %.loc20_15 br !while.body.loc20 else br !while.done.loc20
// CHECK:STDOUT:
// CHECK:STDOUT: !while.body.loc20:
// CHECK:STDOUT: %E.ref: <function> = name_reference "E", file.%E
// CHECK:STDOUT: %.loc21_12.1: init bool = call %E.ref()
// CHECK:STDOUT: %.loc21_12.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc21_12.3: ref bool = temporary %.loc21_12.2, %.loc21_12.1
// CHECK:STDOUT: %.loc21_12.4: bool = bind_value %.loc21_12.3
// CHECK:STDOUT: if %.loc21_12.4 br !if.then.loc21 else br !if.else.loc21
// CHECK:STDOUT: %.loc21_12: init bool = call %E.ref()
// CHECK:STDOUT: %.loc21_14: bool = value_of_initializer %.loc21_12
// CHECK:STDOUT: if %.loc21_14 br !if.then.loc21 else br !if.else.loc21
// CHECK:STDOUT:
// CHECK:STDOUT: !if.then.loc21:
// CHECK:STDOUT: br !while.cond.loc20
// CHECK:STDOUT:
// CHECK:STDOUT: !if.else.loc21:
// CHECK:STDOUT: %F.ref: <function> = name_reference "F", file.%F
// CHECK:STDOUT: %.loc22_12.1: init bool = call %F.ref()
// CHECK:STDOUT: %.loc22_12.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc22_12.3: ref bool = temporary %.loc22_12.2, %.loc22_12.1
// CHECK:STDOUT: %.loc22_12.4: bool = bind_value %.loc22_12.3
// CHECK:STDOUT: if %.loc22_12.4 br !if.then.loc22 else br !if.else.loc22
// CHECK:STDOUT: %.loc22_12: init bool = call %F.ref()
// CHECK:STDOUT: %.loc22_14: bool = value_of_initializer %.loc22_12
// CHECK:STDOUT: if %.loc22_14 br !if.then.loc22 else br !if.else.loc22
// CHECK:STDOUT:
// CHECK:STDOUT: !if.then.loc22:
// CHECK:STDOUT: br !while.done.loc20
@@ -126,22 +114,18 @@ fn While() {
// CHECK:STDOUT:
// CHECK:STDOUT: !while.done.loc20:
// CHECK:STDOUT: %G.ref: <function> = name_reference "G", file.%G
// CHECK:STDOUT: %.loc24_10.1: init bool = call %G.ref()
// CHECK:STDOUT: %.loc24_10.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc24_10.3: ref bool = temporary %.loc24_10.2, %.loc24_10.1
// CHECK:STDOUT: %.loc24_10.4: bool = bind_value %.loc24_10.3
// CHECK:STDOUT: if %.loc24_10.4 br !if.then.loc24 else br !if.else.loc24
// CHECK:STDOUT: %.loc24_10: init bool = call %G.ref()
// CHECK:STDOUT: %.loc24_12: bool = value_of_initializer %.loc24_10
// CHECK:STDOUT: if %.loc24_12 br !if.then.loc24 else br !if.else.loc24
// CHECK:STDOUT:
// CHECK:STDOUT: !if.then.loc24:
// CHECK:STDOUT: br !while.cond.loc17
// CHECK:STDOUT:
// CHECK:STDOUT: !if.else.loc24:
// CHECK:STDOUT: %H.ref: <function> = name_reference "H", file.%H
// CHECK:STDOUT: %.loc25_10.1: init bool = call %H.ref()
// CHECK:STDOUT: %.loc25_10.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc25_10.3: ref bool = temporary %.loc25_10.2, %.loc25_10.1
// CHECK:STDOUT: %.loc25_10.4: bool = bind_value %.loc25_10.3
// CHECK:STDOUT: if %.loc25_10.4 br !if.then.loc25 else br !if.else.loc25
// CHECK:STDOUT: %.loc25_10: init bool = call %H.ref()
// CHECK:STDOUT: %.loc25_12: bool = value_of_initializer %.loc25_10
// CHECK:STDOUT: if %.loc25_12 br !if.then.loc25 else br !if.else.loc25
// CHECK:STDOUT:
// CHECK:STDOUT: !if.then.loc25:
// CHECK:STDOUT: br !while.done.loc17
+3 -5
View File
@@ -44,11 +44,9 @@ fn While() {
// CHECK:STDOUT:
// CHECK:STDOUT: !while.cond:
// CHECK:STDOUT: %Cond.ref: <function> = name_reference "Cond", file.%Cond
// CHECK:STDOUT: %.loc15_14.1: init bool = call %Cond.ref()
// CHECK:STDOUT: %.loc15_14.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc15_14.3: ref bool = temporary %.loc15_14.2, %.loc15_14.1
// CHECK:STDOUT: %.loc15_14.4: bool = bind_value %.loc15_14.3
// CHECK:STDOUT: if %.loc15_14.4 br !while.body else br !while.done
// CHECK:STDOUT: %.loc15_14: init bool = call %Cond.ref()
// CHECK:STDOUT: %.loc15_16: bool = value_of_initializer %.loc15_14
// CHECK:STDOUT: if %.loc15_16 br !while.body else br !while.done
// CHECK:STDOUT:
// CHECK:STDOUT: !while.body:
// CHECK:STDOUT: %G.ref: <function> = name_reference "G", file.%G
+3 -5
View File
@@ -43,11 +43,9 @@ fn While() {
// CHECK:STDOUT:
// CHECK:STDOUT: !while.cond:
// CHECK:STDOUT: %Cond.ref: <function> = name_reference "Cond", file.%Cond
// CHECK:STDOUT: %.loc15_14.1: init bool = call %Cond.ref()
// CHECK:STDOUT: %.loc15_14.2: ref bool = temporary_storage
// CHECK:STDOUT: %.loc15_14.3: ref bool = temporary %.loc15_14.2, %.loc15_14.1
// CHECK:STDOUT: %.loc15_14.4: bool = bind_value %.loc15_14.3
// CHECK:STDOUT: if %.loc15_14.4 br !while.body else br !while.done
// CHECK:STDOUT: %.loc15_14: init bool = call %Cond.ref()
// CHECK:STDOUT: %.loc15_16: bool = value_of_initializer %.loc15_14
// CHECK:STDOUT: if %.loc15_16 br !while.body else br !while.done
// CHECK:STDOUT:
// CHECK:STDOUT: !while.body:
// CHECK:STDOUT: %G.ref: <function> = name_reference "G", file.%G
@@ -58,4 +58,17 @@ auto HandleValueAsReference(FunctionContext& context, SemIR::NodeId node_id,
context.SetLocal(node_id, context.GetLocal(node.value_id));
}
auto HandleValueOfInitializer(FunctionContext& context, SemIR::NodeId node_id,
SemIR::ValueOfInitializer node) -> void {
CARBON_CHECK(SemIR::GetExpressionCategory(context.sem_ir(), node.init_id) ==
SemIR::ExpressionCategory::Initializing);
CARBON_CHECK(
SemIR::GetValueRepresentation(context.sem_ir(), node.type_id).kind ==
SemIR::ValueRepresentation::Copy);
CARBON_CHECK(
SemIR::GetInitializingRepresentation(context.sem_ir(), node.type_id)
.kind == SemIR::InitializingRepresentation::ByCopy);
context.SetLocal(node_id, context.GetLocal(node.init_id));
}
} // namespace Carbon::Lower
+1 -4
View File
@@ -30,8 +30,5 @@ fn G() -> i32 {
// CHECK:STDOUT: %array.index2 = getelementptr inbounds [3 x i32], ptr %temp, i32 0, i32 2
// CHECK:STDOUT: store i32 3, ptr %array.index2, align 4
// CHECK:STDOUT: %F = call i32 @F(ptr %temp, i32 1)
// CHECK:STDOUT: %temp3 = alloca i32, align 4
// CHECK:STDOUT: store i32 %F, ptr %temp3, align 4
// CHECK:STDOUT: %1 = load i32, ptr %temp3, align 4
// CHECK:STDOUT: ret i32 %1
// CHECK:STDOUT: ret i32 %F
// CHECK:STDOUT: }
+1 -4
View File
@@ -38,8 +38,5 @@ fn Run() -> i32 {
// CHECK:STDOUT: %b = getelementptr inbounds { i32, ptr }, ptr %c, i32 0, i32 1
// CHECK:STDOUT: store ptr %c, ptr %b, align 8
// CHECK:STDOUT: %F = call i32 @F(ptr %c)
// CHECK:STDOUT: %temp = alloca i32, align 4
// CHECK:STDOUT: store i32 %F, ptr %temp, align 4
// CHECK:STDOUT: %1 = load i32, ptr %temp, align 4
// CHECK:STDOUT: ret i32 %1
// CHECK:STDOUT: ret i32 %F
// CHECK:STDOUT: }
+1 -4
View File
@@ -25,9 +25,6 @@ fn F(p: C*) {
// CHECK:STDOUT:
// CHECK:STDOUT: define void @F(ptr %p) {
// CHECK:STDOUT: %Get = call i32 @Get(ptr %p)
// CHECK:STDOUT: %temp = alloca i32, align 4
// CHECK:STDOUT: store i32 %Get, ptr %temp, align 4
// CHECK:STDOUT: %1 = load i32, ptr %temp, align 4
// CHECK:STDOUT: call void @Set(ptr %p, i32 %1)
// CHECK:STDOUT: call void @Set(ptr %p, i32 %Get)
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
+7 -13
View File
@@ -23,23 +23,17 @@ fn Select(b: bool) -> i32 {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define i32 @Select(i1 %b) {
// CHECK:STDOUT: br i1 %b, label %1, label %3
// CHECK:STDOUT: br i1 %b, label %1, label %2
// CHECK:STDOUT:
// CHECK:STDOUT: 1: ; preds = %0
// CHECK:STDOUT: %F = call i32 @F()
// CHECK:STDOUT: %temp = alloca i32, align 4
// CHECK:STDOUT: store i32 %F, ptr %temp, align 4
// CHECK:STDOUT: %2 = load i32, ptr %temp, align 4
// CHECK:STDOUT: br label %5
// CHECK:STDOUT: br label %3
// CHECK:STDOUT:
// CHECK:STDOUT: 3: ; preds = %0
// CHECK:STDOUT: 2: ; preds = %0
// CHECK:STDOUT: %G = call i32 @G()
// CHECK:STDOUT: %temp1 = alloca i32, align 4
// CHECK:STDOUT: store i32 %G, ptr %temp1, align 4
// CHECK:STDOUT: %4 = load i32, ptr %temp1, align 4
// CHECK:STDOUT: br label %5
// CHECK:STDOUT: br label %3
// CHECK:STDOUT:
// CHECK:STDOUT: 5: ; preds = %3, %1
// CHECK:STDOUT: %6 = phi i32 [ %2, %1 ], [ %4, %3 ]
// CHECK:STDOUT: ret i32 %6
// CHECK:STDOUT: 3: ; preds = %2, %1
// CHECK:STDOUT: %4 = phi i32 [ %F, %1 ], [ %G, %2 ]
// CHECK:STDOUT: ret i32 %4
// CHECK:STDOUT: }
+6 -12
View File
@@ -24,19 +24,13 @@ fn And() -> bool {
// CHECK:STDOUT:
// CHECK:STDOUT: define i1 @And() {
// CHECK:STDOUT: %F = call i1 @F()
// CHECK:STDOUT: %temp = alloca i1, align 1
// CHECK:STDOUT: store i1 %F, ptr %temp, align 1
// CHECK:STDOUT: %1 = load i1, ptr %temp, align 1
// CHECK:STDOUT: br i1 %1, label %2, label %4
// CHECK:STDOUT: br i1 %F, label %1, label %2
// CHECK:STDOUT:
// CHECK:STDOUT: 2: ; preds = %0
// CHECK:STDOUT: 1: ; preds = %0
// CHECK:STDOUT: %G = call i1 @G()
// CHECK:STDOUT: %temp1 = alloca i1, align 1
// CHECK:STDOUT: store i1 %G, ptr %temp1, align 1
// CHECK:STDOUT: %3 = load i1, ptr %temp1, align 1
// CHECK:STDOUT: br label %4
// CHECK:STDOUT: br label %2
// CHECK:STDOUT:
// CHECK:STDOUT: 4: ; preds = %2, %0
// CHECK:STDOUT: %5 = phi i1 [ false, %0 ], [ %3, %2 ]
// CHECK:STDOUT: ret i1 %5
// CHECK:STDOUT: 2: ; preds = %1, %0
// CHECK:STDOUT: %3 = phi i1 [ false, %0 ], [ %G, %1 ]
// CHECK:STDOUT: ret i1 %3
// CHECK:STDOUT: }
+7 -13
View File
@@ -24,20 +24,14 @@ fn Or() -> bool {
// CHECK:STDOUT:
// CHECK:STDOUT: define i1 @Or() {
// CHECK:STDOUT: %F = call i1 @F()
// CHECK:STDOUT: %temp = alloca i1, align 1
// CHECK:STDOUT: store i1 %F, ptr %temp, align 1
// CHECK:STDOUT: %1 = load i1, ptr %temp, align 1
// CHECK:STDOUT: %2 = xor i1 %1, true
// CHECK:STDOUT: br i1 %2, label %3, label %5
// CHECK:STDOUT: %1 = xor i1 %F, true
// CHECK:STDOUT: br i1 %1, label %2, label %3
// CHECK:STDOUT:
// CHECK:STDOUT: 3: ; preds = %0
// CHECK:STDOUT: 2: ; preds = %0
// CHECK:STDOUT: %G = call i1 @G()
// CHECK:STDOUT: %temp1 = alloca i1, align 1
// CHECK:STDOUT: store i1 %G, ptr %temp1, align 1
// CHECK:STDOUT: %4 = load i1, ptr %temp1, align 1
// CHECK:STDOUT: br label %5
// CHECK:STDOUT: br label %3
// CHECK:STDOUT:
// CHECK:STDOUT: 5: ; preds = %3, %0
// CHECK:STDOUT: %6 = phi i1 [ true, %0 ], [ %4, %3 ]
// CHECK:STDOUT: ret i1 %6
// CHECK:STDOUT: 3: ; preds = %2, %0
// CHECK:STDOUT: %4 = phi i1 [ true, %0 ], [ %G, %2 ]
// CHECK:STDOUT: ret i1 %4
// CHECK:STDOUT: }
+1 -4
View File
@@ -25,8 +25,5 @@ fn F() -> i32 {
// CHECK:STDOUT: %n = alloca i32, align 4
// CHECK:STDOUT: store i32 0, ptr %n, align 4
// CHECK:STDOUT: %G = call i32 @G(ptr %n)
// CHECK:STDOUT: %temp = alloca i32, align 4
// CHECK:STDOUT: store i32 %G, ptr %temp, align 4
// CHECK:STDOUT: %1 = load i32, ptr %temp, align 4
// CHECK:STDOUT: ret i32 %1
// CHECK:STDOUT: ret i32 %G
// CHECK:STDOUT: }
+11 -20
View File
@@ -28,37 +28,28 @@ fn While() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: br label %0
// CHECK:STDOUT:
// CHECK:STDOUT: 0: ; preds = %entry, %8, %4
// CHECK:STDOUT: 0: ; preds = %entry, %5, %2
// CHECK:STDOUT: %A = call i1 @A()
// CHECK:STDOUT: %temp = alloca i1, align 1
// CHECK:STDOUT: store i1 %A, ptr %temp, align 1
// CHECK:STDOUT: %1 = load i1, ptr %temp, align 1
// CHECK:STDOUT: br i1 %1, label %2, label %9
// CHECK:STDOUT: br i1 %A, label %1, label %6
// CHECK:STDOUT:
// CHECK:STDOUT: 2: ; preds = %0
// CHECK:STDOUT: 1: ; preds = %0
// CHECK:STDOUT: %B = call i1 @B()
// CHECK:STDOUT: %temp1 = alloca i1, align 1
// CHECK:STDOUT: store i1 %B, ptr %temp1, align 1
// CHECK:STDOUT: %3 = load i1, ptr %temp1, align 1
// CHECK:STDOUT: br i1 %3, label %4, label %5
// CHECK:STDOUT: br i1 %B, label %2, label %3
// CHECK:STDOUT:
// CHECK:STDOUT: 4: ; preds = %2
// CHECK:STDOUT: 2: ; preds = %1
// CHECK:STDOUT: br label %0
// CHECK:STDOUT:
// CHECK:STDOUT: 5: ; preds = %2
// CHECK:STDOUT: 3: ; preds = %1
// CHECK:STDOUT: %C = call i1 @C()
// CHECK:STDOUT: %temp2 = alloca i1, align 1
// CHECK:STDOUT: store i1 %C, ptr %temp2, align 1
// CHECK:STDOUT: %6 = load i1, ptr %temp2, align 1
// CHECK:STDOUT: br i1 %6, label %7, label %8
// CHECK:STDOUT: br i1 %C, label %4, label %5
// CHECK:STDOUT:
// CHECK:STDOUT: 7: ; preds = %5
// CHECK:STDOUT: br label %9
// CHECK:STDOUT: 4: ; preds = %3
// CHECK:STDOUT: br label %6
// CHECK:STDOUT:
// CHECK:STDOUT: 8: ; preds = %5
// CHECK:STDOUT: 5: ; preds = %3
// CHECK:STDOUT: br label %0
// CHECK:STDOUT:
// CHECK:STDOUT: 9: ; preds = %7, %0
// CHECK:STDOUT: 6: ; preds = %4, %0
// CHECK:STDOUT: ret void
// CHECK:STDOUT:
// CHECK:STDOUT: ; uselistorder directives
+13 -22
View File
@@ -37,39 +37,30 @@ fn While() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: br label %0
// CHECK:STDOUT:
// CHECK:STDOUT: 0: ; preds = %entry, %2
// CHECK:STDOUT: 0: ; preds = %entry, %1
// CHECK:STDOUT: %Cond = call i1 @Cond()
// CHECK:STDOUT: %temp = alloca i1, align 1
// CHECK:STDOUT: store i1 %Cond, ptr %temp, align 1
// CHECK:STDOUT: %1 = load i1, ptr %temp, align 1
// CHECK:STDOUT: br i1 %1, label %2, label %3
// CHECK:STDOUT: br i1 %Cond, label %1, label %2
// CHECK:STDOUT:
// CHECK:STDOUT: 2: ; preds = %0
// CHECK:STDOUT: 1: ; preds = %0
// CHECK:STDOUT: call void @F()
// CHECK:STDOUT: br label %0
// CHECK:STDOUT:
// CHECK:STDOUT: 3: ; preds = %0
// CHECK:STDOUT: 2: ; preds = %0
// CHECK:STDOUT: %Cond1 = call i1 @Cond()
// CHECK:STDOUT: %temp2 = alloca i1, align 1
// CHECK:STDOUT: store i1 %Cond1, ptr %temp2, align 1
// CHECK:STDOUT: %4 = load i1, ptr %temp2, align 1
// CHECK:STDOUT: br i1 %4, label %5, label %9
// CHECK:STDOUT: br i1 %Cond1, label %3, label %6
// CHECK:STDOUT:
// CHECK:STDOUT: 5: ; preds = %7, %3
// CHECK:STDOUT: %Cond3 = call i1 @Cond()
// CHECK:STDOUT: %temp4 = alloca i1, align 1
// CHECK:STDOUT: store i1 %Cond3, ptr %temp4, align 1
// CHECK:STDOUT: %6 = load i1, ptr %temp4, align 1
// CHECK:STDOUT: br i1 %6, label %7, label %8
// CHECK:STDOUT: 3: ; preds = %4, %2
// CHECK:STDOUT: %Cond2 = call i1 @Cond()
// CHECK:STDOUT: br i1 %Cond2, label %4, label %5
// CHECK:STDOUT:
// CHECK:STDOUT: 7: ; preds = %5
// CHECK:STDOUT: 4: ; preds = %3
// CHECK:STDOUT: call void @G()
// CHECK:STDOUT: br label %5
// CHECK:STDOUT: br label %3
// CHECK:STDOUT:
// CHECK:STDOUT: 8: ; preds = %5
// CHECK:STDOUT: br label %9
// CHECK:STDOUT: 5: ; preds = %3
// CHECK:STDOUT: br label %6
// CHECK:STDOUT:
// CHECK:STDOUT: 9: ; preds = %8, %3
// CHECK:STDOUT: 6: ; preds = %5, %2
// CHECK:STDOUT: ret void
// CHECK:STDOUT:
// CHECK:STDOUT: ; uselistorder directives
+3 -6
View File
@@ -36,16 +36,13 @@ fn While() {
// CHECK:STDOUT:
// CHECK:STDOUT: 1: ; preds = %0
// CHECK:STDOUT: %Cond = call i1 @Cond()
// CHECK:STDOUT: %temp = alloca i1, align 1
// CHECK:STDOUT: store i1 %Cond, ptr %temp, align 1
// CHECK:STDOUT: %2 = load i1, ptr %temp, align 1
// CHECK:STDOUT: br i1 %2, label %3, label %4
// CHECK:STDOUT: br i1 %Cond, label %2, label %3
// CHECK:STDOUT:
// CHECK:STDOUT: 3: ; preds = %1
// CHECK:STDOUT: 2: ; preds = %1
// CHECK:STDOUT: call void @G()
// CHECK:STDOUT: ret void
// CHECK:STDOUT:
// CHECK:STDOUT: 4: ; preds = %1
// CHECK:STDOUT: 3: ; preds = %1
// CHECK:STDOUT: call void @H()
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
+4 -7
View File
@@ -33,18 +33,15 @@ fn While() {
// CHECK:STDOUT: call void @F()
// CHECK:STDOUT: br label %1
// CHECK:STDOUT:
// CHECK:STDOUT: 1: ; preds = %3, %0
// CHECK:STDOUT: 1: ; preds = %2, %0
// CHECK:STDOUT: %Cond = call i1 @Cond()
// CHECK:STDOUT: %temp = alloca i1, align 1
// CHECK:STDOUT: store i1 %Cond, ptr %temp, align 1
// CHECK:STDOUT: %2 = load i1, ptr %temp, align 1
// CHECK:STDOUT: br i1 %2, label %3, label %4
// CHECK:STDOUT: br i1 %Cond, label %2, label %3
// CHECK:STDOUT:
// CHECK:STDOUT: 3: ; preds = %1
// CHECK:STDOUT: 2: ; preds = %1
// CHECK:STDOUT: call void @G()
// CHECK:STDOUT: br label %1
// CHECK:STDOUT:
// CHECK:STDOUT: 4: ; preds = %1
// CHECK:STDOUT: 3: ; preds = %1
// CHECK:STDOUT: call void @H()
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
+3
View File
@@ -226,6 +226,7 @@ static auto GetTypePrecedence(NodeKind kind) -> int {
case TupleValue::Kind:
case UnaryOperatorNot::Kind:
case ValueAsReference::Kind:
case ValueOfInitializer::Kind:
case VarStorage::Kind:
CARBON_FATAL() << "GetTypePrecedence for non-type node kind " << kind;
}
@@ -426,6 +427,7 @@ auto File::StringifyTypeExpression(NodeId outer_node_id,
case TupleValue::Kind:
case UnaryOperatorNot::Kind:
case ValueAsReference::Kind:
case ValueOfInitializer::Kind:
case VarStorage::Kind:
// We don't need to handle stringification for nodes that don't show up
// in errors, but make it clear what's going on so that it's clearer
@@ -508,6 +510,7 @@ auto GetExpressionCategory(const File& file, NodeId node_id)
case TupleType::Kind:
case UnaryOperatorNot::Kind:
case UnboundFieldType::Kind:
case ValueOfInitializer::Kind:
return value_category;
case Builtin::Kind: {
+2 -2
View File
@@ -404,8 +404,8 @@ struct InitializingRepresentation {
// The type has no initializing representation. This is used for empty
// types, where no initialization is necessary.
None,
// An initializing expression produces a value, which is copied into the
// initialized object.
// An initializing expression produces an object representation by value,
// which is copied into the initialized object.
ByCopy,
// An initializing expression takes a location as input, which is
// initialized as a side effect of evaluating the expression.
+1
View File
@@ -71,6 +71,7 @@ CARBON_SEM_IR_NODE_KIND(TupleValue)
CARBON_SEM_IR_NODE_KIND(UnaryOperatorNot)
CARBON_SEM_IR_NODE_KIND(UnboundFieldType)
CARBON_SEM_IR_NODE_KIND(ValueAsReference)
CARBON_SEM_IR_NODE_KIND(ValueOfInitializer)
CARBON_SEM_IR_NODE_KIND(VarStorage)
#undef CARBON_SEM_IR_NODE_KIND
+9
View File
@@ -541,6 +541,15 @@ struct ValueAsReference {
NodeId value_id;
};
struct ValueOfInitializer {
static constexpr auto Kind =
NodeKind::ValueOfInitializer.Define("value_of_initializer");
Parse::Node parse_node;
TypeId type_id;
NodeId init_id;
};
struct VarStorage {
static constexpr auto Kind = NodeKind::VarStorage.Define("var");