mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:00:13 +01:00
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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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: }
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user