Add builtins for compound assignment operators. (#5335)

Provide builtins for compound assignments instead of defining them in
the prelude as a use of a binary operator and an assignment. This allows
us to lower compound assignment directly to LLVM operations instead of
producing a function call. In the short term this also allows us to
define a type-generic compound assignment in the prelude.
This commit is contained in:
Richard Smith
2025-04-21 20:38:11 +00:00
committed by GitHub
parent 2bdea71c25
commit b5ae988a08
39 changed files with 1373 additions and 312 deletions
+20 -53
View File
@@ -106,77 +106,44 @@ impl forall [N:! IntLiteral()] Int(N) as RightShift {
// Compound assignments.
// TODO: Once we can lower specific functions, make these generic.
// Each function has a commented out generic signature.
// impl forall [N:! IntLiteral()] Int(N) as AddAssign {
impl i32 as AddAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self + other;
}
impl forall [N:! IntLiteral()] Int(N) as AddAssign {
fn Op[addr self: Self*](other: Self) = "int.sadd_assign";
}
// impl forall [N:! IntLiteral()] Int(N) as BitAndAssign {
impl i32 as BitAndAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self & other;
}
impl forall [N:! IntLiteral()] Int(N) as BitAndAssign {
fn Op[addr self: Self*](other: Self) = "int.and_assign";
}
// impl forall [N:! IntLiteral()] Int(N) as BitOrAssign {
impl i32 as BitOrAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self | other;
}
impl forall [N:! IntLiteral()] Int(N) as BitOrAssign {
fn Op[addr self: Self*](other: Self) = "int.or_assign";
}
// impl forall [N:! IntLiteral()] Int(N) as BitXorAssign {
impl i32 as BitXorAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self ^ other;
}
impl forall [N:! IntLiteral()] Int(N) as BitXorAssign {
fn Op[addr self: Self*](other: Self) = "int.xor_assign";
}
// impl forall [N:! IntLiteral()] Int(N) as DivAssign {
impl i32 as DivAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self / other;
}
impl forall [N:! IntLiteral()] Int(N) as DivAssign {
fn Op[addr self: Self*](other: Self) = "int.sdiv_assign";
}
// impl forall [N:! IntLiteral()] Int(N) as LeftShiftAssign {
impl i32 as LeftShiftAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self << other;
}
impl forall [N:! IntLiteral()] Int(N) as LeftShiftAssign {
fn Op[addr self: Self*](other: Self) = "int.left_shift_assign";
}
// impl forall [N:! IntLiteral()] Int(N) as ModAssign {
impl i32 as ModAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self % other;
}
impl forall [N:! IntLiteral()] Int(N) as ModAssign {
fn Op[addr self: Self*](other: Self) = "int.smod_assign";
}
// impl forall [N:! IntLiteral()] Int(N) as MulAssign {
impl i32 as MulAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self * other;
}
impl forall [N:! IntLiteral()] Int(N) as MulAssign {
fn Op[addr self: Self*](other: Self) = "int.smul_assign";
}
// impl forall [N:! IntLiteral()] Int(N) as RightShiftAssign {
impl i32 as RightShiftAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self >> other;
}
impl forall [N:! IntLiteral()] Int(N) as RightShiftAssign {
fn Op[addr self: Self*](other: Self) = "int.right_shift_assign";
}
// impl forall [N:! IntLiteral()] Int(N) as SubAssign {
impl i32 as SubAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self - other;
}
impl forall [N:! IntLiteral()] Int(N) as SubAssign {
fn Op[addr self: Self*](other: Self) = "int.ssub_assign";
}
// Increment and decrement.
+20 -53
View File
@@ -117,77 +117,44 @@ impl forall [N:! IntLiteral()] UInt(N) as RightShift {
// Compound assignments.
// TODO: Once we can lower specific functions, make these generic.
// Each function has a commented out generic signature.
// impl forall [N:! IntLiteral()] UInt(N) as AddAssign {
impl u32 as AddAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self + other;
}
impl forall [N:! IntLiteral()] UInt(N) as AddAssign {
fn Op[addr self: Self*](other: Self) = "int.uadd_assign";
}
// impl forall [N:! IntLiteral()] UInt(N) as BitAndAssign {
impl u32 as BitAndAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self & other;
}
impl forall [N:! IntLiteral()] UInt(N) as BitAndAssign {
fn Op[addr self: Self*](other: Self) = "int.and_assign";
}
// impl forall [N:! IntLiteral()] UInt(N) as BitOrAssign {
impl u32 as BitOrAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self | other;
}
impl forall [N:! IntLiteral()] UInt(N) as BitOrAssign {
fn Op[addr self: Self*](other: Self) = "int.or_assign";
}
// impl forall [N:! IntLiteral()] UInt(N) as BitXorAssign {
impl u32 as BitXorAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self ^ other;
}
impl forall [N:! IntLiteral()] UInt(N) as BitXorAssign {
fn Op[addr self: Self*](other: Self) = "int.xor_assign";
}
// impl forall [N:! IntLiteral()] UInt(N) as DivAssign {
impl u32 as DivAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self / other;
}
impl forall [N:! IntLiteral()] UInt(N) as DivAssign {
fn Op[addr self: Self*](other: Self) = "int.udiv_assign";
}
// impl forall [N:! IntLiteral()] UInt(N) as LeftShiftAssign {
impl u32 as LeftShiftAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self << other;
}
impl forall [N:! IntLiteral()] UInt(N) as LeftShiftAssign {
fn Op[addr self: Self*](other: Self) = "int.left_shift_assign";
}
// impl forall [N:! IntLiteral()] UInt(N) as ModAssign {
impl u32 as ModAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self % other;
}
impl forall [N:! IntLiteral()] UInt(N) as ModAssign {
fn Op[addr self: Self*](other: Self) = "int.umod_assign";
}
// impl forall [N:! IntLiteral()] UInt(N) as MulAssign {
impl u32 as MulAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self * other;
}
impl forall [N:! IntLiteral()] UInt(N) as MulAssign {
fn Op[addr self: Self*](other: Self) = "int.umul_assign";
}
// impl forall [N:! IntLiteral()] UInt(N) as RightShiftAssign {
impl u32 as RightShiftAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self >> other;
}
impl forall [N:! IntLiteral()] UInt(N) as RightShiftAssign {
fn Op[addr self: Self*](other: Self) = "int.right_shift_assign";
}
// impl forall [N:! IntLiteral()] UInt(N) as SubAssign {
impl u32 as SubAssign {
fn Op[addr self: Self*](other: Self) {
*self = *self - other;
}
impl forall [N:! IntLiteral()] UInt(N) as SubAssign {
fn Op[addr self: Self*](other: Self) = "int.usub_assign";
}
// Increment and decrement.
+16 -1
View File
@@ -1394,7 +1394,22 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context,
case SemIR::BuiltinFunctionKind::PrintChar:
case SemIR::BuiltinFunctionKind::PrintInt:
case SemIR::BuiltinFunctionKind::ReadChar: {
case SemIR::BuiltinFunctionKind::ReadChar:
case SemIR::BuiltinFunctionKind::IntSAddAssign:
case SemIR::BuiltinFunctionKind::IntSSubAssign:
case SemIR::BuiltinFunctionKind::IntSMulAssign:
case SemIR::BuiltinFunctionKind::IntSDivAssign:
case SemIR::BuiltinFunctionKind::IntSModAssign:
case SemIR::BuiltinFunctionKind::IntUAddAssign:
case SemIR::BuiltinFunctionKind::IntUSubAssign:
case SemIR::BuiltinFunctionKind::IntUMulAssign:
case SemIR::BuiltinFunctionKind::IntUDivAssign:
case SemIR::BuiltinFunctionKind::IntUModAssign:
case SemIR::BuiltinFunctionKind::IntAndAssign:
case SemIR::BuiltinFunctionKind::IntOrAssign:
case SemIR::BuiltinFunctionKind::IntXorAssign:
case SemIR::BuiltinFunctionKind::IntLeftShiftAssign:
case SemIR::BuiltinFunctionKind::IntRightShiftAssign: {
// These are runtime-only builtins.
// TODO: Consider tracking this on the `BuiltinFunctionKind`.
return SemIR::ConstantId::NotConstant;
+8 -8
View File
@@ -696,16 +696,16 @@ static auto IsValidBuiltinDeclaration(Context& context,
const SemIR::Function& function,
SemIR::BuiltinFunctionKind builtin_kind)
-> bool {
// Find the list of call parameters other than the implicit return slot.
auto call_params = context.inst_blocks().Get(function.call_params_id);
if (function.return_slot_pattern_id.has_value()) {
call_params = call_params.drop_back();
}
// Form the list of parameter types for the declaration.
llvm::SmallVector<SemIR::TypeId> param_type_ids;
auto implicit_param_patterns =
context.inst_blocks().GetOrEmpty(function.implicit_param_patterns_id);
auto param_patterns =
context.inst_blocks().GetOrEmpty(function.param_patterns_id);
param_type_ids.reserve(implicit_param_patterns.size() +
param_patterns.size());
for (auto param_id : llvm::concat<const SemIR::InstId>(
implicit_param_patterns, param_patterns)) {
param_type_ids.reserve(call_params.size());
for (auto param_id : call_params) {
// TODO: We also need to track whether the parameter is declared with
// `var`.
param_type_ids.push_back(context.insts().Get(param_id).type_id());
+11 -11
View File
@@ -56,7 +56,7 @@ let c: array(i32, ConvertToU32(3))* = &a;
// CHECK:STDOUT: %bound_method.c6f: <bound method> = bound_method %int_3.822, %Convert.specific_fn.8a8 [concrete]
// CHECK:STDOUT: %int_3.1ba: Core.IntLiteral = int_value 3 [concrete]
// CHECK:STDOUT: %array_type: type = array_type %int_3.1ba, %i32 [concrete]
// CHECK:STDOUT: %ptr: type = ptr_type %array_type [concrete]
// CHECK:STDOUT: %ptr.f01: type = ptr_type %array_type [concrete]
// CHECK:STDOUT: %tuple.type: type = tuple_type (Core.IntLiteral, Core.IntLiteral, Core.IntLiteral) [concrete]
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [concrete]
// CHECK:STDOUT: %Convert.bound.b30: <bound method> = bound_method %int_3.1ba, %Convert.956 [concrete]
@@ -175,20 +175,20 @@ let c: array(i32, ConvertToU32(3))* = &a;
// CHECK:STDOUT: }
// CHECK:STDOUT: %a: ref %array_type = bind_name a, %a.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %b.patt: %ptr = binding_pattern b
// CHECK:STDOUT: %b.patt: %ptr.f01 = binding_pattern b
// CHECK:STDOUT: }
// CHECK:STDOUT: %.loc15: type = splice_block %ptr.loc15 [concrete = constants.%ptr] {
// CHECK:STDOUT: %.loc15: type = splice_block %ptr.loc15 [concrete = constants.%ptr.f01] {
// CHECK:STDOUT: %int_32.loc15: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32.loc15: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %int_3.loc15: Core.IntLiteral = int_value 3 [concrete = constants.%int_3.1ba]
// CHECK:STDOUT: %array_type.loc15: type = array_type %int_3.loc15, %i32.loc15 [concrete = constants.%array_type]
// CHECK:STDOUT: %ptr.loc15: type = ptr_type %array_type.loc15 [concrete = constants.%ptr]
// CHECK:STDOUT: %ptr.loc15: type = ptr_type %array_type.loc15 [concrete = constants.%ptr.f01]
// CHECK:STDOUT: }
// CHECK:STDOUT: %b: %ptr = bind_name b, @__global_init.%addr.loc15
// CHECK:STDOUT: %b: %ptr.f01 = bind_name b, @__global_init.%addr.loc15
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %c.patt: %ptr = binding_pattern c
// CHECK:STDOUT: %c.patt: %ptr.f01 = binding_pattern c
// CHECK:STDOUT: }
// CHECK:STDOUT: %.loc16_35: type = splice_block %ptr.loc16 [concrete = constants.%ptr] {
// CHECK:STDOUT: %.loc16_35: type = splice_block %ptr.loc16 [concrete = constants.%ptr.f01] {
// CHECK:STDOUT: %int_32.loc16: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32.loc16: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %ConvertToU32.ref: %ConvertToU32.type = name_ref ConvertToU32, %ConvertToU32.decl [concrete = constants.%ConvertToU32]
@@ -211,9 +211,9 @@ let c: array(i32, ConvertToU32(3))* = &a;
// CHECK:STDOUT: %.loc16_33.3: Core.IntLiteral = value_of_initializer %int.convert_checked.loc16_33.2 [concrete = constants.%int_3.1ba]
// CHECK:STDOUT: %.loc16_33.4: Core.IntLiteral = converted %int.convert_checked.loc16_33.1, %.loc16_33.3 [concrete = constants.%int_3.1ba]
// CHECK:STDOUT: %array_type.loc16: type = array_type %.loc16_33.4, %i32.loc16 [concrete = constants.%array_type]
// CHECK:STDOUT: %ptr.loc16: type = ptr_type %array_type.loc16 [concrete = constants.%ptr]
// CHECK:STDOUT: %ptr.loc16: type = ptr_type %array_type.loc16 [concrete = constants.%ptr.f01]
// CHECK:STDOUT: }
// CHECK:STDOUT: %c: %ptr = bind_name c, @__global_init.%addr.loc16
// CHECK:STDOUT: %c: %ptr.f01 = bind_name c, @__global_init.%addr.loc16
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Add.1(%a.param_patt: %i32, %b.param_patt: %i32) -> %i32 = "int.sadd";
@@ -257,9 +257,9 @@ let c: array(i32, ConvertToU32(3))* = &a;
// CHECK:STDOUT: %.loc14_1: init %array_type = converted %.loc14_40.1, %.loc14_40.11 [concrete = constants.%array]
// CHECK:STDOUT: assign file.%a.var, %.loc14_1
// CHECK:STDOUT: %a.ref.loc15: ref %array_type = name_ref a, file.%a
// CHECK:STDOUT: %addr.loc15: %ptr = addr_of %a.ref.loc15
// CHECK:STDOUT: %addr.loc15: %ptr.f01 = addr_of %a.ref.loc15
// CHECK:STDOUT: %a.ref.loc16: ref %array_type = name_ref a, file.%a
// CHECK:STDOUT: %addr.loc16: %ptr = addr_of %a.ref.loc16
// CHECK:STDOUT: %addr.loc16: %ptr.f01 = addr_of %a.ref.loc16
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
+47
View File
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/and_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/and_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.and_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.and_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.and_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.and_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.and_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.and_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.and_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.and_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.and_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.and_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/left_shift_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/left_shift_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.left_shift_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
fn MixedTypes(a: i32*, b: i64) = "int.left_shift_assign";
fn CallMixed(a: i32*, b: i64) {
MixedTypes(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.left_shift_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.left_shift_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.left_shift_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.left_shift_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.left_shift_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.left_shift_assign";
+47
View File
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/or_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/or_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.or_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.or_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.or_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.or_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.or_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.or_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.or_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.or_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.or_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.or_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/right_shift_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/right_shift_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.right_shift_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
fn MixedTypes(a: i32*, b: i64) = "int.right_shift_assign";
fn CallMixed(a: i32*, b: i64) {
MixedTypes(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.right_shift_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.right_shift_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.right_shift_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.right_shift_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.right_shift_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.right_shift_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/sadd_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/sadd_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.sadd_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.sadd_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.sadd_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.sadd_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.sadd_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.sadd_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.sadd_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.sadd_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.sadd_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.sadd_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/sdiv_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/sdiv_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.sdiv_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.sdiv_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.sdiv_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.sdiv_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.sdiv_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.sdiv_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.sdiv_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.sdiv_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.sdiv_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.sdiv_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/smod_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/smod_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.smod_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.smod_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.smod_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.smod_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.smod_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.smod_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.smod_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.smod_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.smod_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.smod_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/smul_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/smul_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.smul_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.smul_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.smul_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.smul_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.smul_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.smul_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.smul_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.smul_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.smul_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.smul_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/ssub_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/ssub_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.ssub_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.ssub_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.ssub_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.ssub_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.ssub_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.ssub_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.ssub_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.ssub_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.ssub_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.ssub_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/uadd_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/uadd_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.uadd_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.uadd_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.uadd_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.uadd_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.uadd_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.uadd_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.uadd_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.uadd_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.uadd_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.uadd_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/udiv_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/udiv_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.udiv_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.udiv_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.udiv_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.udiv_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.udiv_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.udiv_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.udiv_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.udiv_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.udiv_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.udiv_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/umod_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/umod_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.umod_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.umod_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.umod_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.umod_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.umod_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.umod_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.umod_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.umod_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.umod_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.umod_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/umul_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/umul_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.umul_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.umul_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.umul_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.umul_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.umul_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.umul_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.umul_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.umul_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.umul_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.umul_assign";
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/usub_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/usub_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.usub_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.usub_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.usub_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.usub_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.usub_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.usub_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.usub_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.usub_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.usub_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.usub_assign";
+47
View File
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/xor_assign.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/xor_assign.carbon
// --- call.carbon
library "[[@TEST_NAME]]";
fn Builtin(a: i32*, b: i32) = "int.xor_assign";
fn Call(a: i32*, b: i32) {
Builtin(a, b);
}
// --- fail_unsized.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_unsized.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.xor_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.xor_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Builtin(a: Core.IntLiteral()*, b: Core.IntLiteral()) = "int.xor_assign";
// --- fail_bad_decl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.xor_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn NotPtr(a: i32, b: i32) = "int.xor_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NotPtr(a: i32, b: i32) = "int.xor_assign";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: error: invalid signature for builtin function "int.xor_assign" [InvalidBuiltinSignature]
// CHECK:STDERR: fn MixedTypes(a: i32*, b: i64) = "int.xor_assign";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn MixedTypes(a: i32*, b: i64) = "int.xor_assign";
+1 -1
View File
@@ -368,5 +368,5 @@ fn Run() {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F[%self.param_patt: %ForwardDeclared.7b34f2.1]() [from "a.carbon"];
// CHECK:STDOUT:
// CHECK:STDOUT: fn @G[addr <unexpected>.inst1161: %ptr.6cf]() [from "a.carbon"];
// CHECK:STDOUT: fn @G[addr <unexpected>.inst1395: %ptr.6cf]() [from "a.carbon"];
// CHECK:STDOUT:
@@ -30,7 +30,7 @@ fn F(N:! i32, a: array(i32, N)*);
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %N.51e, %Convert.specific_fn [symbolic]
// CHECK:STDOUT: %int.convert_checked: init Core.IntLiteral = call %bound_method(%N.51e) [symbolic]
// CHECK:STDOUT: %array_type: type = array_type %int.convert_checked, %i32 [symbolic]
// CHECK:STDOUT: %ptr: type = ptr_type %array_type [symbolic]
// CHECK:STDOUT: %ptr.0ad: type = ptr_type %array_type [symbolic]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: }
@@ -52,16 +52,16 @@ fn F(N:! i32, a: array(i32, N)*);
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
// CHECK:STDOUT: %N.patt.loc11_6.1: %i32 = symbolic_binding_pattern N, 0 [symbolic = %N.patt.loc11_6.2 (constants.%N.patt.8e2)]
// CHECK:STDOUT: %a.patt: @F.%ptr.loc11_31.2 (%ptr) = binding_pattern a
// CHECK:STDOUT: %a.param_patt: @F.%ptr.loc11_31.2 (%ptr) = value_param_pattern %a.patt, call_param0
// CHECK:STDOUT: %a.patt: @F.%ptr.loc11_31.2 (%ptr.0ad) = binding_pattern a
// CHECK:STDOUT: %a.param_patt: @F.%ptr.loc11_31.2 (%ptr.0ad) = value_param_pattern %a.patt, call_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %.loc11_10: type = splice_block %i32.loc11_10 [concrete = constants.%i32] {
// CHECK:STDOUT: %int_32.loc11_10: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32.loc11_10: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: }
// CHECK:STDOUT: %N.loc11_6.1: %i32 = bind_symbolic_name N, 0 [symbolic = %N.loc11_6.2 (constants.%N.51e)]
// CHECK:STDOUT: %a.param: @F.%ptr.loc11_31.2 (%ptr) = value_param call_param0
// CHECK:STDOUT: %.loc11_31: type = splice_block %ptr.loc11_31.1 [symbolic = %ptr.loc11_31.2 (constants.%ptr)] {
// CHECK:STDOUT: %a.param: @F.%ptr.loc11_31.2 (%ptr.0ad) = value_param call_param0
// CHECK:STDOUT: %.loc11_31: type = splice_block %ptr.loc11_31.1 [symbolic = %ptr.loc11_31.2 (constants.%ptr.0ad)] {
// CHECK:STDOUT: %int_32.loc11_24: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32.loc11_24: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %N.ref: %i32 = name_ref N, %N.loc11_6.1 [symbolic = %N.loc11_6.2 (constants.%N.51e)]
@@ -73,9 +73,9 @@ fn F(N:! i32, a: array(i32, N)*);
// CHECK:STDOUT: %.loc11_29.1: Core.IntLiteral = value_of_initializer %int.convert_checked.loc11_29.1 [symbolic = %int.convert_checked.loc11_29.2 (constants.%int.convert_checked)]
// CHECK:STDOUT: %.loc11_29.2: Core.IntLiteral = converted %N.ref, %.loc11_29.1 [symbolic = %int.convert_checked.loc11_29.2 (constants.%int.convert_checked)]
// CHECK:STDOUT: %array_type.loc11_30.1: type = array_type %.loc11_29.2, %i32.loc11_24 [symbolic = %array_type.loc11_30.2 (constants.%array_type)]
// CHECK:STDOUT: %ptr.loc11_31.1: type = ptr_type %array_type.loc11_30.1 [symbolic = %ptr.loc11_31.2 (constants.%ptr)]
// CHECK:STDOUT: %ptr.loc11_31.1: type = ptr_type %array_type.loc11_30.1 [symbolic = %ptr.loc11_31.2 (constants.%ptr.0ad)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %a: @F.%ptr.loc11_31.2 (%ptr) = bind_name a, %a.param
// CHECK:STDOUT: %a: @F.%ptr.loc11_31.2 (%ptr.0ad) = bind_name a, %a.param
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -86,9 +86,9 @@ fn F(N:! i32, a: array(i32, N)*);
// CHECK:STDOUT: %bound_method.loc11_29.3: <bound method> = bound_method %N.loc11_6.2, constants.%Convert.specific_fn [symbolic = %bound_method.loc11_29.3 (constants.%bound_method)]
// CHECK:STDOUT: %int.convert_checked.loc11_29.2: init Core.IntLiteral = call %bound_method.loc11_29.3(%N.loc11_6.2) [symbolic = %int.convert_checked.loc11_29.2 (constants.%int.convert_checked)]
// CHECK:STDOUT: %array_type.loc11_30.2: type = array_type %int.convert_checked.loc11_29.2, constants.%i32 [symbolic = %array_type.loc11_30.2 (constants.%array_type)]
// CHECK:STDOUT: %ptr.loc11_31.2: type = ptr_type %array_type.loc11_30.2 [symbolic = %ptr.loc11_31.2 (constants.%ptr)]
// CHECK:STDOUT: %ptr.loc11_31.2: type = ptr_type %array_type.loc11_30.2 [symbolic = %ptr.loc11_31.2 (constants.%ptr.0ad)]
// CHECK:STDOUT:
// CHECK:STDOUT: fn(%N.patt.loc11_6.1: %i32, %a.param_patt: @F.%ptr.loc11_31.2 (%ptr));
// CHECK:STDOUT: fn(%N.patt.loc11_6.1: %i32, %a.param_patt: @F.%ptr.loc11_31.2 (%ptr.0ad));
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F(constants.%N.51e) {
@@ -98,6 +98,6 @@ fn F(N:! i32, a: array(i32, N)*);
// CHECK:STDOUT: %bound_method.loc11_29.3 => constants.%bound_method
// CHECK:STDOUT: %int.convert_checked.loc11_29.2 => constants.%int.convert_checked
// CHECK:STDOUT: %array_type.loc11_30.2 => constants.%array_type
// CHECK:STDOUT: %ptr.loc11_31.2 => constants.%ptr
// CHECK:STDOUT: %ptr.loc11_31.2 => constants.%ptr.0ad
// CHECK:STDOUT: }
// CHECK:STDOUT:
+20 -20
View File
@@ -65,7 +65,7 @@ fn PartiallyConstant(t: type) -> i32 {
// CHECK:STDOUT: %false: bool = bool_literal false [concrete]
// CHECK:STDOUT: %Constant.type: type = fn_type @Constant [concrete]
// CHECK:STDOUT: %Constant: %Constant.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: %PartiallyConstant.type: type = fn_type @PartiallyConstant [concrete]
// CHECK:STDOUT: %PartiallyConstant: %PartiallyConstant.type = struct_value () [concrete]
// CHECK:STDOUT: }
@@ -253,7 +253,7 @@ fn PartiallyConstant(t: type) -> i32 {
// CHECK:STDOUT: !if.expr.else.loc23:
// CHECK:STDOUT: %int_32.loc23_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32.loc23_32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %ptr.loc23: type = ptr_type %i32.loc23_32 [concrete = constants.%ptr]
// CHECK:STDOUT: %ptr.loc23: type = ptr_type %i32.loc23_32 [concrete = constants.%ptr.235]
// CHECK:STDOUT: br !if.expr.result.loc23(%ptr.loc23)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.result.loc23:
@@ -263,12 +263,12 @@ fn PartiallyConstant(t: type) -> i32 {
// CHECK:STDOUT: !.loc23_7:
// CHECK:STDOUT: %v: ref %i32 = bind_name v, %v.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %w.patt: %ptr = binding_pattern w
// CHECK:STDOUT: %.loc24_3: %ptr = var_pattern %w.patt
// CHECK:STDOUT: %w.patt: %ptr.235 = binding_pattern w
// CHECK:STDOUT: %.loc24_3: %ptr.235 = var_pattern %w.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %w.var: ref %ptr = var w
// CHECK:STDOUT: %w.var: ref %ptr.235 = var w
// CHECK:STDOUT: %v.ref: ref %i32 = name_ref v, %v
// CHECK:STDOUT: %addr: %ptr = addr_of %v.ref
// CHECK:STDOUT: %addr: %ptr.235 = addr_of %v.ref
// CHECK:STDOUT: assign %w.var, %addr
// CHECK:STDOUT: br !.loc24_13
// CHECK:STDOUT:
@@ -284,17 +284,17 @@ fn PartiallyConstant(t: type) -> i32 {
// CHECK:STDOUT: !if.expr.else.loc24:
// CHECK:STDOUT: %int_32.loc24_33: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32.loc24_33: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %ptr.loc24: type = ptr_type %i32.loc24_33 [concrete = constants.%ptr]
// CHECK:STDOUT: %ptr.loc24: type = ptr_type %i32.loc24_33 [concrete = constants.%ptr.235]
// CHECK:STDOUT: br !if.expr.result.loc24(%ptr.loc24)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.result.loc24:
// CHECK:STDOUT: %.loc24_10: type = block_arg !if.expr.result.loc24 [concrete = constants.%ptr]
// CHECK:STDOUT: %.loc24_10: type = block_arg !if.expr.result.loc24 [concrete = constants.%ptr.235]
// CHECK:STDOUT: br !.loc24_7
// CHECK:STDOUT:
// CHECK:STDOUT: !.loc24_7:
// CHECK:STDOUT: %w: ref %ptr = bind_name w, %w.var
// CHECK:STDOUT: %w.ref: ref %ptr = name_ref w, %w
// CHECK:STDOUT: %.loc25_11: %ptr = bind_value %w.ref
// CHECK:STDOUT: %w: ref %ptr.235 = bind_name w, %w.var
// CHECK:STDOUT: %w.ref: ref %ptr.235 = name_ref w, %w
// CHECK:STDOUT: %.loc25_11: %ptr.235 = bind_value %w.ref
// CHECK:STDOUT: %.loc25_10.1: ref %i32 = deref %.loc25_11
// CHECK:STDOUT: %.loc25_10.2: %i32 = bind_value %.loc25_10.1
// CHECK:STDOUT: return %.loc25_10.2
@@ -337,12 +337,12 @@ fn PartiallyConstant(t: type) -> i32 {
// CHECK:STDOUT: !.loc29_7:
// CHECK:STDOUT: %v: ref %i32 = bind_name v, %v.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %w.patt: %ptr = binding_pattern w
// CHECK:STDOUT: %.loc30_3: %ptr = var_pattern %w.patt
// CHECK:STDOUT: %w.patt: %ptr.235 = binding_pattern w
// CHECK:STDOUT: %.loc30_3: %ptr.235 = var_pattern %w.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %w.var: ref %ptr = var w
// CHECK:STDOUT: %w.var: ref %ptr.235 = var w
// CHECK:STDOUT: %v.ref: ref %i32 = name_ref v, %v
// CHECK:STDOUT: %addr: %ptr = addr_of %v.ref
// CHECK:STDOUT: %addr: %ptr.235 = addr_of %v.ref
// CHECK:STDOUT: assign %w.var, %addr
// CHECK:STDOUT: br !.loc30_13
// CHECK:STDOUT:
@@ -357,17 +357,17 @@ fn PartiallyConstant(t: type) -> i32 {
// CHECK:STDOUT: !if.expr.else.loc30:
// CHECK:STDOUT: %int_32.loc30: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32.loc30: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %ptr: type = ptr_type %i32.loc30 [concrete = constants.%ptr]
// CHECK:STDOUT: %ptr: type = ptr_type %i32.loc30 [concrete = constants.%ptr.235]
// CHECK:STDOUT: br !if.expr.result.loc30(%ptr)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.result.loc30:
// CHECK:STDOUT: %.loc30_10: type = block_arg !if.expr.result.loc30 [concrete = constants.%ptr]
// CHECK:STDOUT: %.loc30_10: type = block_arg !if.expr.result.loc30 [concrete = constants.%ptr.235]
// CHECK:STDOUT: br !.loc30_7
// CHECK:STDOUT:
// CHECK:STDOUT: !.loc30_7:
// CHECK:STDOUT: %w: ref %ptr = bind_name w, %w.var
// CHECK:STDOUT: %w.ref: ref %ptr = name_ref w, %w
// CHECK:STDOUT: %.loc31_11: %ptr = bind_value %w.ref
// CHECK:STDOUT: %w: ref %ptr.235 = bind_name w, %w.var
// CHECK:STDOUT: %w.ref: ref %ptr.235 = name_ref w, %w
// CHECK:STDOUT: %.loc31_11: %ptr.235 = bind_value %w.ref
// CHECK:STDOUT: %.loc31_10.1: ref %i32 = deref %.loc31_11
// CHECK:STDOUT: %.loc31_10.2: %i32 = bind_value %.loc31_10.1
// CHECK:STDOUT: return %.loc31_10.2
@@ -94,7 +94,7 @@ class C {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x: %i32 = bind_name x, <unexpected>.inst1083.loc27_14
// CHECK:STDOUT: %x: %i32 = bind_name x, <unexpected>.inst1317.loc27_14
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %y.patt: %i32 = binding_pattern y
// CHECK:STDOUT: %.loc37: %i32 = var_pattern %y.patt
+4 -4
View File
@@ -71,21 +71,21 @@ impl () as I where .X = {.a = true, .b = (1, 2)} and .X = {.a = false, .b = (3,
// CHECK:STDOUT: %struct: %struct_type.a.b.fe2 = struct_value (%true, %tuple) [concrete]
// CHECK:STDOUT: %false: bool = bool_literal false [concrete]
// CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [concrete]
// CHECK:STDOUT: %Op.type.111: type = fn_type @Op.13 [concrete]
// CHECK:STDOUT: %Op.type.111: type = fn_type @Op.23 [concrete]
// CHECK:STDOUT: %Sub.impl_witness_table.d7b = impl_witness_table (imports.%Core.import_ref.6c4), @impl.bf8 [concrete]
// CHECK:STDOUT: %Sub.impl_witness.37d: <witness> = impl_witness %Sub.impl_witness_table.d7b [concrete]
// CHECK:STDOUT: %Sub.facet: %Sub.type = facet_value Core.IntLiteral, (%Sub.impl_witness.37d) [concrete]
// CHECK:STDOUT: %.07b: type = fn_type_with_self_type %Op.type.111, %Sub.facet [concrete]
// CHECK:STDOUT: %Op.type.2b9: type = fn_type @Op.14 [concrete]
// CHECK:STDOUT: %Op.type.2b9: type = fn_type @Op.24 [concrete]
// CHECK:STDOUT: %Op.667: %Op.type.2b9 = struct_value () [concrete]
// CHECK:STDOUT: %Op.bound.645: <bound method> = bound_method %int_3, %Op.667 [concrete]
// CHECK:STDOUT: %int_4: Core.IntLiteral = int_value 4 [concrete]
// CHECK:STDOUT: %Op.type.784: type = fn_type @Op.15 [concrete]
// CHECK:STDOUT: %Op.type.784: type = fn_type @Op.25 [concrete]
// CHECK:STDOUT: %Div.impl_witness_table.381 = impl_witness_table (imports.%Core.import_ref.dfd), @impl.f0e [concrete]
// CHECK:STDOUT: %Div.impl_witness.ec4: <witness> = impl_witness %Div.impl_witness_table.381 [concrete]
// CHECK:STDOUT: %Div.facet: %Div.type = facet_value Core.IntLiteral, (%Div.impl_witness.ec4) [concrete]
// CHECK:STDOUT: %.d13: type = fn_type_with_self_type %Op.type.784, %Div.facet [concrete]
// CHECK:STDOUT: %Op.type.c38: type = fn_type @Op.16 [concrete]
// CHECK:STDOUT: %Op.type.c38: type = fn_type @Op.26 [concrete]
// CHECK:STDOUT: %Op.553: %Op.type.c38 = struct_value () [concrete]
// CHECK:STDOUT: %Op.bound.2e7: <bound method> = bound_method %int_4, %Op.553 [concrete]
// CHECK:STDOUT: %I_where.type: type = facet_type <@I where %impl.elem0 = %struct> [concrete]
@@ -42,12 +42,12 @@ var d: i32 = c[-10];
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete]
// CHECK:STDOUT: %array: %array_type = tuple_value (%int_42.c68, %int_42.c68) [concrete]
// CHECK:STDOUT: %int_10: Core.IntLiteral = int_value 10 [concrete]
// CHECK:STDOUT: %Op.type.e42: type = fn_type @Op.13 [concrete]
// CHECK:STDOUT: %Op.type.e42: type = fn_type @Op.23 [concrete]
// CHECK:STDOUT: %Negate.impl_witness_table.e09 = impl_witness_table (imports.%Core.import_ref.c15), @impl.8cb [concrete]
// CHECK:STDOUT: %Negate.impl_witness.561: <witness> = impl_witness %Negate.impl_witness_table.e09 [concrete]
// CHECK:STDOUT: %Negate.facet: %Negate.type = facet_value Core.IntLiteral, (%Negate.impl_witness.561) [concrete]
// CHECK:STDOUT: %.63a: type = fn_type_with_self_type %Op.type.e42, %Negate.facet [concrete]
// CHECK:STDOUT: %Op.type.1be: type = fn_type @Op.14 [concrete]
// CHECK:STDOUT: %Op.type.1be: type = fn_type @Op.24 [concrete]
// CHECK:STDOUT: %Op.bba: %Op.type.1be = struct_value () [concrete]
// CHECK:STDOUT: %Op.bound: <bound method> = bound_method %int_10, %Op.bba [concrete]
// CHECK:STDOUT: %int_-10.06d: Core.IntLiteral = int_value -10 [concrete]
+2 -2
View File
@@ -895,7 +895,7 @@ fn F() {
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.956, @Convert.2(%int_32) [concrete]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_1.5b8, %Convert.specific_fn [concrete]
// CHECK:STDOUT: %int_1.5d2: %i32 = int_value 1 [concrete]
// CHECK:STDOUT: %ptr: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -947,7 +947,7 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
// CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a
// CHECK:STDOUT: %addr: %ptr = addr_of %a.ref
// CHECK:STDOUT: %addr: %ptr.235 = addr_of %a.ref
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
+3 -3
View File
@@ -33,7 +33,7 @@ fn F() -> i32 {
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.956, @Convert.2(%int_32) [concrete]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_0.5c6, %Convert.specific_fn [concrete]
// CHECK:STDOUT: %int_0.6a9: %i32 = int_value 0 [concrete]
// CHECK:STDOUT: %ptr: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -83,9 +83,9 @@ fn F() -> i32 {
// CHECK:STDOUT: }
// CHECK:STDOUT: %n: ref %i32 = bind_name n, %n.var
// CHECK:STDOUT: %n.ref: ref %i32 = name_ref n, %n
// CHECK:STDOUT: %addr.loc13_13: %ptr = addr_of %n.ref
// CHECK:STDOUT: %addr.loc13_13: %ptr.235 = addr_of %n.ref
// CHECK:STDOUT: %.loc13_12: ref %i32 = deref %addr.loc13_13
// CHECK:STDOUT: %addr.loc13_11: %ptr = addr_of %.loc13_12
// CHECK:STDOUT: %addr.loc13_11: %ptr.235 = addr_of %.loc13_12
// CHECK:STDOUT: %.loc13_10.1: ref %i32 = deref %addr.loc13_11
// CHECK:STDOUT: %.loc13_10.2: %i32 = bind_value %.loc13_10.1
// CHECK:STDOUT: return %.loc13_10.2
+10 -10
View File
@@ -35,7 +35,7 @@ fn F() -> i32 {
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.956, @Convert.2(%int_32) [concrete]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_0.5c6, %Convert.specific_fn [concrete]
// CHECK:STDOUT: %int_0.6a9: %i32 = int_value 0 [concrete]
// CHECK:STDOUT: %ptr: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -85,21 +85,21 @@ fn F() -> i32 {
// CHECK:STDOUT: }
// CHECK:STDOUT: %n: ref %i32 = bind_name n, %n.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %p.patt: %ptr = binding_pattern p
// CHECK:STDOUT: %.loc13_3: %ptr = var_pattern %p.patt
// CHECK:STDOUT: %p.patt: %ptr.235 = binding_pattern p
// CHECK:STDOUT: %.loc13_3: %ptr.235 = var_pattern %p.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %p.var: ref %ptr = var p
// CHECK:STDOUT: %p.var: ref %ptr.235 = var p
// CHECK:STDOUT: %n.ref: ref %i32 = name_ref n, %n
// CHECK:STDOUT: %addr: %ptr = addr_of %n.ref
// CHECK:STDOUT: %addr: %ptr.235 = addr_of %n.ref
// CHECK:STDOUT: assign %p.var, %addr
// CHECK:STDOUT: %.loc13_13: type = splice_block %ptr [concrete = constants.%ptr] {
// CHECK:STDOUT: %.loc13_13: type = splice_block %ptr [concrete = constants.%ptr.235] {
// CHECK:STDOUT: %int_32.loc13: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32.loc13: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %ptr: type = ptr_type %i32.loc13 [concrete = constants.%ptr]
// CHECK:STDOUT: %ptr: type = ptr_type %i32.loc13 [concrete = constants.%ptr.235]
// CHECK:STDOUT: }
// CHECK:STDOUT: %p: ref %ptr = bind_name p, %p.var
// CHECK:STDOUT: %p.ref: ref %ptr = name_ref p, %p
// CHECK:STDOUT: %.loc15_11: %ptr = bind_value %p.ref
// CHECK:STDOUT: %p: ref %ptr.235 = bind_name p, %p.var
// CHECK:STDOUT: %p.ref: ref %ptr.235 = name_ref p, %p
// CHECK:STDOUT: %.loc15_11: %ptr.235 = bind_value %p.ref
// CHECK:STDOUT: %.loc15_10.1: ref %i32 = deref %.loc15_11
// CHECK:STDOUT: %.loc15_10.2: %i32 = bind_value %.loc15_10.1
// CHECK:STDOUT: return %.loc15_10.2
+18 -18
View File
@@ -39,7 +39,7 @@ var a: i32* = a_ref;
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.956, @Convert.2(%int_32) [concrete]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_0.5c6, %Convert.specific_fn [concrete]
// CHECK:STDOUT: %int_0.6a9: %i32 = int_value 0 [concrete]
// CHECK:STDOUT: %ptr: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -69,16 +69,16 @@ var a: i32* = a_ref;
// CHECK:STDOUT: }
// CHECK:STDOUT: %a_orig: ref %i32 = bind_name a_orig, %a_orig.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %a_ref.patt: %ptr = binding_pattern a_ref
// CHECK:STDOUT: %.loc5_1: %ptr = var_pattern %a_ref.patt
// CHECK:STDOUT: %a_ref.patt: %ptr.235 = binding_pattern a_ref
// CHECK:STDOUT: %.loc5_1: %ptr.235 = var_pattern %a_ref.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %a_ref.var: ref %ptr = var a_ref
// CHECK:STDOUT: %.loc5_15: type = splice_block %ptr [concrete = constants.%ptr] {
// CHECK:STDOUT: %a_ref.var: ref %ptr.235 = var a_ref
// CHECK:STDOUT: %.loc5_15: type = splice_block %ptr [concrete = constants.%ptr.235] {
// CHECK:STDOUT: %int_32.loc5: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32.loc5: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %ptr: type = ptr_type %i32.loc5 [concrete = constants.%ptr]
// CHECK:STDOUT: %ptr: type = ptr_type %i32.loc5 [concrete = constants.%ptr.235]
// CHECK:STDOUT: }
// CHECK:STDOUT: %a_ref: ref %ptr = bind_name a_ref, %a_ref.var
// CHECK:STDOUT: %a_ref: ref %ptr.235 = bind_name a_ref, %a_ref.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
@@ -92,7 +92,7 @@ var a: i32* = a_ref;
// CHECK:STDOUT: %.loc4: init %i32 = converted %int_0, %int.convert_checked [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: assign file.%a_orig.var, %.loc4
// CHECK:STDOUT: %a_orig.ref: ref %i32 = name_ref a_orig, file.%a_orig
// CHECK:STDOUT: %addr: %ptr = addr_of %a_orig.ref
// CHECK:STDOUT: %addr: %ptr.235 = addr_of %a_orig.ref
// CHECK:STDOUT: assign file.%a_ref.var, %addr
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -102,12 +102,12 @@ var a: i32* = a_ref;
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %ptr: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: %ptr.9e1: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Implicit.a_orig = import_ref Implicit//default, a_orig, unloaded
// CHECK:STDOUT: %Implicit.a_ref: ref %ptr = import_ref Implicit//default, a_ref, loaded
// CHECK:STDOUT: %Implicit.a_ref: ref %ptr.9e1 = import_ref Implicit//default, a_ref, loaded
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
// CHECK:STDOUT: .Int = %Core.Int
// CHECK:STDOUT: import Core//prelude
@@ -126,22 +126,22 @@ var a: i32* = a_ref;
// CHECK:STDOUT: %default.import = import <none>
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %a.patt: %ptr = binding_pattern a
// CHECK:STDOUT: %.loc4_1: %ptr = var_pattern %a.patt
// CHECK:STDOUT: %a.patt: %ptr.9e1 = binding_pattern a
// CHECK:STDOUT: %.loc4_1: %ptr.9e1 = var_pattern %a.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %a.var: ref %ptr = var a
// CHECK:STDOUT: %.loc4_11: type = splice_block %ptr [concrete = constants.%ptr] {
// CHECK:STDOUT: %a.var: ref %ptr.9e1 = var a
// CHECK:STDOUT: %.loc4_11: type = splice_block %ptr [concrete = constants.%ptr.9e1] {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %ptr: type = ptr_type %i32 [concrete = constants.%ptr]
// CHECK:STDOUT: %ptr: type = ptr_type %i32 [concrete = constants.%ptr.9e1]
// CHECK:STDOUT: }
// CHECK:STDOUT: %a: ref %ptr = bind_name a, %a.var
// CHECK:STDOUT: %a: ref %ptr.9e1 = bind_name a, %a.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %a_ref.ref: ref %ptr = name_ref a_ref, imports.%Implicit.a_ref
// CHECK:STDOUT: %.loc4: %ptr = bind_value %a_ref.ref
// CHECK:STDOUT: %a_ref.ref: ref %ptr.9e1 = name_ref a_ref, imports.%Implicit.a_ref
// CHECK:STDOUT: %.loc4: %ptr.9e1 = bind_value %a_ref.ref
// CHECK:STDOUT: assign file.%a.var, %.loc4
// CHECK:STDOUT: return
// CHECK:STDOUT: }
+3 -3
View File
@@ -331,7 +331,7 @@ var c_bad: C({.a = 3, .b = 4}) = F();
// CHECK:STDOUT: }
// CHECK:STDOUT: %Implicit.import_ref.c81: %struct_type.a.b.5ca = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)]
// CHECK:STDOUT: %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357]
// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1160 [no loc], unloaded
// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1394 [no loc], unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -508,7 +508,7 @@ var c_bad: C({.a = 3, .b = 4}) = F();
// CHECK:STDOUT: }
// CHECK:STDOUT: %Implicit.import_ref.c81: %struct_type.a.b = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)]
// CHECK:STDOUT: %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357]
// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1160 [no loc], unloaded
// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1394 [no loc], unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -626,7 +626,7 @@ var c_bad: C({.a = 3, .b = 4}) = F();
// CHECK:STDOUT: }
// CHECK:STDOUT: %Implicit.import_ref.c81: %struct_type.a.b.5ca = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)]
// CHECK:STDOUT: %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357]
// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1160 [no loc], unloaded
// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1394 [no loc], unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -43,12 +43,12 @@ var b: i32 = a.(-10);
// CHECK:STDOUT: %int_6.e56: %i32 = int_value 6 [concrete]
// CHECK:STDOUT: %tuple: %tuple.type.d07 = tuple_value (%int_12.1e1, %int_6.e56) [concrete]
// CHECK:STDOUT: %int_10: Core.IntLiteral = int_value 10 [concrete]
// CHECK:STDOUT: %Op.type.e42: type = fn_type @Op.13 [concrete]
// CHECK:STDOUT: %Op.type.e42: type = fn_type @Op.23 [concrete]
// CHECK:STDOUT: %Negate.impl_witness_table.e09 = impl_witness_table (imports.%Core.import_ref.c15), @impl.8cb [concrete]
// CHECK:STDOUT: %Negate.impl_witness.561: <witness> = impl_witness %Negate.impl_witness_table.e09 [concrete]
// CHECK:STDOUT: %Negate.facet: %Negate.type = facet_value Core.IntLiteral, (%Negate.impl_witness.561) [concrete]
// CHECK:STDOUT: %.63a: type = fn_type_with_self_type %Op.type.e42, %Negate.facet [concrete]
// CHECK:STDOUT: %Op.type.1be: type = fn_type @Op.14 [concrete]
// CHECK:STDOUT: %Op.type.1be: type = fn_type @Op.24 [concrete]
// CHECK:STDOUT: %Op.bba: %Op.type.1be = struct_value () [concrete]
// CHECK:STDOUT: %Op.bound: <bound method> = bound_method %int_10, %Op.bba [concrete]
// CHECK:STDOUT: %int_-10: Core.IntLiteral = int_value -10 [concrete]
+3 -3
View File
@@ -361,7 +361,7 @@ var c_bad: C((3, 4)) = F();
// CHECK:STDOUT: }
// CHECK:STDOUT: %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)]
// CHECK:STDOUT: %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357]
// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1197 [no loc], unloaded
// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1431 [no loc], unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -554,7 +554,7 @@ var c_bad: C((3, 4)) = F();
// CHECK:STDOUT: }
// CHECK:STDOUT: %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)]
// CHECK:STDOUT: %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357]
// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1197 [no loc], unloaded
// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1431 [no loc], unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -673,7 +673,7 @@ var c_bad: C((3, 4)) = F();
// CHECK:STDOUT: }
// CHECK:STDOUT: %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)]
// CHECK:STDOUT: %Implicit.import_ref.8f2: <witness> = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357]
// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1197 [no loc], unloaded
// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1431 [no loc], unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
+5
View File
@@ -7,6 +7,7 @@
#include "common/vlog.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/sem_ir/file.h"
#include "toolchain/sem_ir/generic.h"
namespace Carbon::Lower {
@@ -171,6 +172,10 @@ auto FunctionContext::FinishInit(SemIR::TypeId type_id, SemIR::InstId dest_id,
}
}
auto FunctionContext::GetTypeOfInst(SemIR::InstId inst_id) -> SemIR::TypeId {
return SemIR::GetTypeOfInstInSpecific(sem_ir(), specific_id(), inst_id);
}
auto FunctionContext::CopyValue(SemIR::TypeId type_id, SemIR::InstId source_id,
SemIR::InstId dest_id) -> void {
switch (auto rep = SemIR::ValueRepr::ForType(sem_ir(), type_id); rep.kind) {
+3
View File
@@ -92,6 +92,9 @@ class FunctionContext {
return file_context_->GetType(type_id);
}
// Returns the type of the given instruction in the current specific.
auto GetTypeOfInst(SemIR::InstId inst_id) -> SemIR::TypeId;
// Returns a lowered value to use for a value of type `type`.
auto GetTypeAsValue() -> llvm::Value* {
return file_context_->GetTypeAsValue();
+152 -106
View File
@@ -64,8 +64,7 @@ static auto GetBuiltinFCmpPredicate(SemIR::BuiltinFunctionKind builtin_kind)
// Returns whether the specified instruction has a signed integer type.
static auto IsSignedInt(FunctionContext& context, SemIR::InstId int_id)
-> bool {
return context.sem_ir().types().IsSignedInt(
context.sem_ir().insts().Get(int_id).type_id());
return context.sem_ir().types().IsSignedInt(context.GetTypeOfInst(int_id));
}
// Creates a zext or sext instruction depending on the signedness of the
@@ -86,13 +85,10 @@ static auto CreateExtOrTrunc(FunctionContext& context, llvm::Value* value,
: context.builder().CreateZExtOrTrunc(value, type, name);
}
// Handles a call to a builtin integer bit shift operator.
static auto HandleIntShift(FunctionContext& context, SemIR::InstId inst_id,
// Create a integer bit shift for a call to a builtin bit shift function.
static auto CreateIntShift(FunctionContext& context,
llvm::Instruction::BinaryOps bin_op,
SemIR::InstId lhs_id, SemIR::InstId rhs_id) -> void {
llvm::Value* lhs = context.GetValue(lhs_id);
llvm::Value* rhs = context.GetValue(rhs_id);
llvm::Value* lhs, llvm::Value* rhs) -> llvm::Value* {
// Weirdly, LLVM requires the operands of bit shift operators to be of the
// same type. We can always use the width of the LHS, because if the RHS
// doesn't fit in that then the cast is out of range anyway. Zero-extending is
@@ -102,8 +98,7 @@ static auto HandleIntShift(FunctionContext& context, SemIR::InstId inst_id,
// negative or greater than or equal to the number of bits in the left-hand
// type.
rhs = context.builder().CreateZExtOrTrunc(rhs, lhs->getType(), "rhs");
context.SetLocal(inst_id, context.builder().CreateBinOp(bin_op, lhs, rhs));
return context.builder().CreateBinOp(bin_op, lhs, rhs);
}
// Handles a call to a builtin integer comparison operator.
@@ -150,6 +145,102 @@ static auto HandleIntComparison(FunctionContext& context, SemIR::InstId inst_id,
GetBuiltinICmpPredicate(builtin_kind, cmp_signed), lhs, rhs));
}
// Creates a binary operator for a call to a builtin for either that operation
// or the corresponding compound assignment.
static auto CreateBinaryOperatorForBuiltin(
FunctionContext& context, SemIR::InstId inst_id,
SemIR::BuiltinFunctionKind builtin_kind, llvm::Value* lhs, llvm::Value* rhs)
-> llvm::Value* {
// TODO: Consider setting this to true in the performance build mode if the
// result type is a signed integer type.
constexpr bool SignedOverflowIsUB = false;
switch (builtin_kind) {
case SemIR::BuiltinFunctionKind::IntSAdd:
case SemIR::BuiltinFunctionKind::IntSAddAssign: {
return context.builder().CreateAdd(lhs, rhs, "",
/*HasNUW=*/false,
/*HasNSW=*/SignedOverflowIsUB);
}
case SemIR::BuiltinFunctionKind::IntSSub:
case SemIR::BuiltinFunctionKind::IntSSubAssign: {
return context.builder().CreateSub(lhs, rhs, "",
/*HasNUW=*/false,
/*HasNSW=*/SignedOverflowIsUB);
}
case SemIR::BuiltinFunctionKind::IntSMul:
case SemIR::BuiltinFunctionKind::IntSMulAssign: {
return context.builder().CreateMul(lhs, rhs, "",
/*HasNUW=*/false,
/*HasNSW=*/SignedOverflowIsUB);
}
case SemIR::BuiltinFunctionKind::IntSDiv:
case SemIR::BuiltinFunctionKind::IntSDivAssign: {
return context.builder().CreateSDiv(lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntSMod:
case SemIR::BuiltinFunctionKind::IntSModAssign: {
return context.builder().CreateSRem(lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntUAdd:
case SemIR::BuiltinFunctionKind::IntUAddAssign: {
return context.builder().CreateAdd(lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntUSub:
case SemIR::BuiltinFunctionKind::IntUSubAssign: {
return context.builder().CreateSub(lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntUMul:
case SemIR::BuiltinFunctionKind::IntUMulAssign: {
return context.builder().CreateMul(lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntUDiv:
case SemIR::BuiltinFunctionKind::IntUDivAssign: {
return context.builder().CreateUDiv(lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntUMod:
case SemIR::BuiltinFunctionKind::IntUModAssign: {
return context.builder().CreateURem(lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntAnd:
case SemIR::BuiltinFunctionKind::IntAndAssign: {
return context.builder().CreateAnd(lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntOr:
case SemIR::BuiltinFunctionKind::IntOrAssign: {
return context.builder().CreateOr(lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntXor:
case SemIR::BuiltinFunctionKind::IntXorAssign: {
return context.builder().CreateXor(lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntLeftShift:
case SemIR::BuiltinFunctionKind::IntLeftShiftAssign: {
return CreateIntShift(context, llvm::Instruction::Shl, lhs, rhs);
}
case SemIR::BuiltinFunctionKind::IntRightShift:
case SemIR::BuiltinFunctionKind::IntRightShiftAssign: {
// TODO: Split each of these builtins into separate signed and unsigned
// builtins rather than working out here whether we're performing an
// arithmetic or logical shift.
auto lhs_id = context.sem_ir().inst_blocks().Get(
context.sem_ir().insts().GetAs<SemIR::Call>(inst_id).args_id)[0];
auto lhs_type_id = context.GetTypeOfInst(lhs_id);
if (builtin_kind == SemIR::BuiltinFunctionKind::IntRightShiftAssign) {
lhs_type_id = context.sem_ir().GetPointeeType(lhs_type_id);
}
return CreateIntShift(context,
context.sem_ir().types().IsSignedInt(lhs_type_id)
? llvm::Instruction::AShr
: llvm::Instruction::LShr,
lhs, rhs);
}
default: {
CARBON_FATAL("Unexpected binary operator {0}", builtin_kind);
}
}
}
// Handles a call to a builtin function.
static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id,
SemIR::BuiltinFunctionKind builtin_kind,
@@ -262,100 +353,56 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id,
llvm::ConstantInt::getSigned(operand->getType(), -1), operand));
return;
}
case SemIR::BuiltinFunctionKind::IntSAdd: {
context.SetLocal(
inst_id, context.builder().CreateAdd(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1]), "",
/*HasNUW=*/false,
/*HasNSW=*/SignedOverflowIsUB));
return;
}
case SemIR::BuiltinFunctionKind::IntSSub: {
context.SetLocal(
inst_id, context.builder().CreateSub(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1]), "",
/*HasNUW=*/false,
/*HasNSW=*/SignedOverflowIsUB));
return;
}
case SemIR::BuiltinFunctionKind::IntSMul: {
context.SetLocal(
inst_id, context.builder().CreateMul(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1]), "",
/*HasNUW=*/false,
/*HasNSW=*/SignedOverflowIsUB));
return;
}
case SemIR::BuiltinFunctionKind::IntSDiv: {
context.SetLocal(
inst_id, context.builder().CreateSDiv(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntSMod: {
context.SetLocal(
inst_id, context.builder().CreateSRem(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntUAdd: {
context.SetLocal(
inst_id, context.builder().CreateAdd(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntUSub: {
context.SetLocal(
inst_id, context.builder().CreateSub(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntUMul: {
context.SetLocal(
inst_id, context.builder().CreateMul(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntUDiv: {
context.SetLocal(
inst_id, context.builder().CreateUDiv(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntUMod: {
context.SetLocal(
inst_id, context.builder().CreateURem(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntAnd: {
context.SetLocal(
inst_id, context.builder().CreateAnd(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntOr: {
context.SetLocal(
inst_id, context.builder().CreateOr(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntXor: {
context.SetLocal(
inst_id, context.builder().CreateXor(context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntLeftShift: {
HandleIntShift(context, inst_id, llvm::Instruction::Shl, arg_ids[0],
arg_ids[1]);
return;
}
case SemIR::BuiltinFunctionKind::IntSAdd:
case SemIR::BuiltinFunctionKind::IntSSub:
case SemIR::BuiltinFunctionKind::IntSMul:
case SemIR::BuiltinFunctionKind::IntSDiv:
case SemIR::BuiltinFunctionKind::IntSMod:
case SemIR::BuiltinFunctionKind::IntUAdd:
case SemIR::BuiltinFunctionKind::IntUSub:
case SemIR::BuiltinFunctionKind::IntUMul:
case SemIR::BuiltinFunctionKind::IntUDiv:
case SemIR::BuiltinFunctionKind::IntUMod:
case SemIR::BuiltinFunctionKind::IntAnd:
case SemIR::BuiltinFunctionKind::IntOr:
case SemIR::BuiltinFunctionKind::IntXor:
case SemIR::BuiltinFunctionKind::IntLeftShift:
case SemIR::BuiltinFunctionKind::IntRightShift: {
HandleIntShift(context, inst_id,
IsSignedInt(context, inst_id) ? llvm::Instruction::AShr
: llvm::Instruction::LShr,
arg_ids[0], arg_ids[1]);
context.SetLocal(inst_id, CreateBinaryOperatorForBuiltin(
context, inst_id, builtin_kind,
context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::IntSAddAssign:
case SemIR::BuiltinFunctionKind::IntSSubAssign:
case SemIR::BuiltinFunctionKind::IntSMulAssign:
case SemIR::BuiltinFunctionKind::IntSDivAssign:
case SemIR::BuiltinFunctionKind::IntSModAssign:
case SemIR::BuiltinFunctionKind::IntUAddAssign:
case SemIR::BuiltinFunctionKind::IntUSubAssign:
case SemIR::BuiltinFunctionKind::IntUMulAssign:
case SemIR::BuiltinFunctionKind::IntUDivAssign:
case SemIR::BuiltinFunctionKind::IntUModAssign:
case SemIR::BuiltinFunctionKind::IntAndAssign:
case SemIR::BuiltinFunctionKind::IntOrAssign:
case SemIR::BuiltinFunctionKind::IntXorAssign:
case SemIR::BuiltinFunctionKind::IntLeftShiftAssign:
case SemIR::BuiltinFunctionKind::IntRightShiftAssign: {
auto* lhs_ptr = context.GetValue(arg_ids[0]);
auto lhs_type_id = context.GetTypeOfInst(arg_ids[0]);
auto pointee_type_id = context.sem_ir().GetPointeeType(lhs_type_id);
// TODO: Factor out the code to create loads and stores, and include alias
// and alignment information.
auto* lhs_value = context.builder().CreateLoad(
context.GetType(pointee_type_id), lhs_ptr);
auto* result = CreateBinaryOperatorForBuiltin(
context, inst_id, builtin_kind, lhs_value,
context.GetValue(arg_ids[1]));
context.builder().CreateStore(result, lhs_ptr);
// TODO: Add a helper to get a "no value representation" value.
context.SetLocal(inst_id, llvm::PoisonValue::get(context.GetType(
context.GetTypeOfInst(inst_id))));
return;
}
case SemIR::BuiltinFunctionKind::IntEq:
@@ -444,8 +491,7 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
std::vector<llvm::Value*> args;
auto inst_type_id = SemIR::GetTypeOfInstInSpecific(
context.sem_ir(), context.specific_id(), inst_id);
auto inst_type_id = context.GetTypeOfInst(inst_id);
if (SemIR::ReturnTypeInfo::ForType(context.sem_ir(), inst_type_id)
.has_return_slot()) {
@@ -454,7 +500,7 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
}
for (auto arg_id : arg_ids) {
auto arg_type_id = context.sem_ir().insts().Get(arg_id).type_id();
auto arg_type_id = context.GetTypeOfInst(arg_id);
if (SemIR::ValueRepr::ForType(context.sem_ir(), arg_type_id).kind !=
SemIR::ValueRepr::None) {
args.push_back(context.GetValue(arg_id));
+240
View File
@@ -69,6 +69,58 @@ fn TestGreater(a: i32, b: i32) -> bool { return Greater(a, b); }
fn GreaterEq(a: i32, b: i32) -> bool = "int.greater_eq";
fn TestGreaterEq(a: i32, b: i32) -> bool { return GreaterEq(a, b); }
// --- compound_assign.carbon
library "[[@TEST_NAME]]";
fn SAdd(a: i32*, b: i32) = "int.sadd_assign";
fn TestSAdd(a: i32*, b: i32) { SAdd(a, b); }
fn SSub(a: i32*, b: i32) = "int.ssub_assign";
fn TestSSub(a: i32*, b: i32) { SSub(a, b); }
fn SMul(a: i32*, b: i32) = "int.smul_assign";
fn TestSMul(a: i32*, b: i32) { SMul(a, b); }
fn SDiv(a: i32*, b: i32) = "int.sdiv_assign";
fn TestSDiv(a: i32*, b: i32) { SDiv(a, b); }
fn SMod(a: i32*, b: i32) = "int.smod_assign";
fn TestSMod(a: i32*, b: i32) { SMod(a, b); }
fn UAdd(a: i32*, b: i32) = "int.uadd_assign";
fn TestUAdd(a: i32*, b: i32) { UAdd(a, b); }
fn USub(a: i32*, b: i32) = "int.usub_assign";
fn TestUSub(a: i32*, b: i32) { USub(a, b); }
fn UMul(a: i32*, b: i32) = "int.umul_assign";
fn TestUMul(a: i32*, b: i32) { UMul(a, b); }
fn UDiv(a: i32*, b: i32) = "int.udiv_assign";
fn TestUDiv(a: i32*, b: i32) { UDiv(a, b); }
fn UMod(a: i32*, b: i32) = "int.umod_assign";
fn TestUMod(a: i32*, b: i32) { UMod(a, b); }
fn And(a: i32*, b: i32) = "int.and_assign";
fn TestAnd(a: i32*, b: i32) { And(a, b); }
fn Or(a: i32*, b: i32) = "int.or_assign";
fn TestOr(a: i32*, b: i32) { Or(a, b); }
fn Xor(a: i32*, b: i32) = "int.xor_assign";
fn TestXor(a: i32*, b: i32) { Xor(a, b); }
fn LeftShift(a: i32*, b: i32) = "int.left_shift_assign";
fn TestLeftShift(a: i32*, b: i32) { LeftShift(a, b); }
fn ArithmeticRightShift(a: i32*, b: u32) = "int.right_shift_assign";
fn TestArithmeticRightShift(a: i32*, b: u32) { ArithmeticRightShift(a, b); }
fn LogicalRightShift(a: u32*, b: u32) = "int.right_shift_assign";
fn TestLogicalRightShift(a: u32*, b: u32) { LogicalRightShift(a, b); }
// --- mixed_shift.carbon
library "[[@TEST_NAME]]";
@@ -351,6 +403,194 @@ fn TestUint32ToUint64(a: u32) -> u64 { return Uint32ToUint64(a); }
// CHECK:STDOUT: !60 = distinct !DISubprogram(name: "TestGreaterEq", linkageName: "_CTestGreaterEq.Main", scope: null, file: !3, line: 59, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !61 = !DILocation(line: 59, column: 51, scope: !60)
// CHECK:STDOUT: !62 = !DILocation(line: 59, column: 44, scope: !60)
// CHECK:STDOUT: ; ModuleID = 'compound_assign.carbon'
// CHECK:STDOUT: source_filename = "compound_assign.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestSAdd.Main(ptr %a, i32 %b) !dbg !4 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.sadd_assign = load i32, ptr %a, align 4, !dbg !7
// CHECK:STDOUT: %int.sadd_assign1 = add i32 %int.sadd_assign, %b, !dbg !7
// CHECK:STDOUT: store i32 %int.sadd_assign1, ptr %a, align 4, !dbg !7
// CHECK:STDOUT: ret void, !dbg !8
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestSSub.Main(ptr %a, i32 %b) !dbg !9 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.ssub_assign = load i32, ptr %a, align 4, !dbg !10
// CHECK:STDOUT: %int.ssub_assign1 = sub i32 %int.ssub_assign, %b, !dbg !10
// CHECK:STDOUT: store i32 %int.ssub_assign1, ptr %a, align 4, !dbg !10
// CHECK:STDOUT: ret void, !dbg !11
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestSMul.Main(ptr %a, i32 %b) !dbg !12 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.smul_assign = load i32, ptr %a, align 4, !dbg !13
// CHECK:STDOUT: %int.smul_assign1 = mul i32 %int.smul_assign, %b, !dbg !13
// CHECK:STDOUT: store i32 %int.smul_assign1, ptr %a, align 4, !dbg !13
// CHECK:STDOUT: ret void, !dbg !14
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestSDiv.Main(ptr %a, i32 %b) !dbg !15 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.sdiv_assign = load i32, ptr %a, align 4, !dbg !16
// CHECK:STDOUT: %int.sdiv_assign1 = sdiv i32 %int.sdiv_assign, %b, !dbg !16
// CHECK:STDOUT: store i32 %int.sdiv_assign1, ptr %a, align 4, !dbg !16
// CHECK:STDOUT: ret void, !dbg !17
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestSMod.Main(ptr %a, i32 %b) !dbg !18 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.smod_assign = load i32, ptr %a, align 4, !dbg !19
// CHECK:STDOUT: %int.smod_assign1 = srem i32 %int.smod_assign, %b, !dbg !19
// CHECK:STDOUT: store i32 %int.smod_assign1, ptr %a, align 4, !dbg !19
// CHECK:STDOUT: ret void, !dbg !20
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestUAdd.Main(ptr %a, i32 %b) !dbg !21 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.uadd_assign = load i32, ptr %a, align 4, !dbg !22
// CHECK:STDOUT: %int.uadd_assign1 = add i32 %int.uadd_assign, %b, !dbg !22
// CHECK:STDOUT: store i32 %int.uadd_assign1, ptr %a, align 4, !dbg !22
// CHECK:STDOUT: ret void, !dbg !23
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestUSub.Main(ptr %a, i32 %b) !dbg !24 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.usub_assign = load i32, ptr %a, align 4, !dbg !25
// CHECK:STDOUT: %int.usub_assign1 = sub i32 %int.usub_assign, %b, !dbg !25
// CHECK:STDOUT: store i32 %int.usub_assign1, ptr %a, align 4, !dbg !25
// CHECK:STDOUT: ret void, !dbg !26
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestUMul.Main(ptr %a, i32 %b) !dbg !27 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.umul_assign = load i32, ptr %a, align 4, !dbg !28
// CHECK:STDOUT: %int.umul_assign1 = mul i32 %int.umul_assign, %b, !dbg !28
// CHECK:STDOUT: store i32 %int.umul_assign1, ptr %a, align 4, !dbg !28
// CHECK:STDOUT: ret void, !dbg !29
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestUDiv.Main(ptr %a, i32 %b) !dbg !30 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.udiv_assign = load i32, ptr %a, align 4, !dbg !31
// CHECK:STDOUT: %int.udiv_assign1 = udiv i32 %int.udiv_assign, %b, !dbg !31
// CHECK:STDOUT: store i32 %int.udiv_assign1, ptr %a, align 4, !dbg !31
// CHECK:STDOUT: ret void, !dbg !32
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestUMod.Main(ptr %a, i32 %b) !dbg !33 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.umod_assign = load i32, ptr %a, align 4, !dbg !34
// CHECK:STDOUT: %int.umod_assign1 = urem i32 %int.umod_assign, %b, !dbg !34
// CHECK:STDOUT: store i32 %int.umod_assign1, ptr %a, align 4, !dbg !34
// CHECK:STDOUT: ret void, !dbg !35
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestAnd.Main(ptr %a, i32 %b) !dbg !36 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.and_assign = load i32, ptr %a, align 4, !dbg !37
// CHECK:STDOUT: %int.and_assign1 = and i32 %int.and_assign, %b, !dbg !37
// CHECK:STDOUT: store i32 %int.and_assign1, ptr %a, align 4, !dbg !37
// CHECK:STDOUT: ret void, !dbg !38
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestOr.Main(ptr %a, i32 %b) !dbg !39 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.or_assign = load i32, ptr %a, align 4, !dbg !40
// CHECK:STDOUT: %int.or_assign1 = or i32 %int.or_assign, %b, !dbg !40
// CHECK:STDOUT: store i32 %int.or_assign1, ptr %a, align 4, !dbg !40
// CHECK:STDOUT: ret void, !dbg !41
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestXor.Main(ptr %a, i32 %b) !dbg !42 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.xor_assign = load i32, ptr %a, align 4, !dbg !43
// CHECK:STDOUT: %int.xor_assign1 = xor i32 %int.xor_assign, %b, !dbg !43
// CHECK:STDOUT: store i32 %int.xor_assign1, ptr %a, align 4, !dbg !43
// CHECK:STDOUT: ret void, !dbg !44
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestLeftShift.Main(ptr %a, i32 %b) !dbg !45 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.left_shift_assign = load i32, ptr %a, align 4, !dbg !46
// CHECK:STDOUT: %int.left_shift_assign1 = shl i32 %int.left_shift_assign, %b, !dbg !46
// CHECK:STDOUT: store i32 %int.left_shift_assign1, ptr %a, align 4, !dbg !46
// CHECK:STDOUT: ret void, !dbg !47
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestArithmeticRightShift.Main(ptr %a, i32 %b) !dbg !48 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.right_shift_assign = load i32, ptr %a, align 4, !dbg !49
// CHECK:STDOUT: %int.right_shift_assign1 = ashr i32 %int.right_shift_assign, %b, !dbg !49
// CHECK:STDOUT: store i32 %int.right_shift_assign1, ptr %a, align 4, !dbg !49
// CHECK:STDOUT: ret void, !dbg !50
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CTestLogicalRightShift.Main(ptr %a, i32 %b) !dbg !51 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.right_shift_assign = load i32, ptr %a, align 4, !dbg !52
// CHECK:STDOUT: %int.right_shift_assign1 = lshr i32 %int.right_shift_assign, %b, !dbg !52
// CHECK:STDOUT: store i32 %int.right_shift_assign1, ptr %a, align 4, !dbg !52
// CHECK:STDOUT: ret void, !dbg !53
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1}
// CHECK:STDOUT: !llvm.dbg.cu = !{!2}
// CHECK:STDOUT:
// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5}
// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3}
// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
// CHECK:STDOUT: !3 = !DIFile(filename: "compound_assign.carbon", directory: "")
// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "TestSAdd", linkageName: "_CTestSAdd.Main", scope: null, file: !3, line: 5, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !5 = !DISubroutineType(types: !6)
// CHECK:STDOUT: !6 = !{}
// CHECK:STDOUT: !7 = !DILocation(line: 5, column: 32, scope: !4)
// CHECK:STDOUT: !8 = !DILocation(line: 5, column: 1, scope: !4)
// CHECK:STDOUT: !9 = distinct !DISubprogram(name: "TestSSub", linkageName: "_CTestSSub.Main", scope: null, file: !3, line: 8, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !10 = !DILocation(line: 8, column: 32, scope: !9)
// CHECK:STDOUT: !11 = !DILocation(line: 8, column: 1, scope: !9)
// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "TestSMul", linkageName: "_CTestSMul.Main", scope: null, file: !3, line: 11, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !13 = !DILocation(line: 11, column: 32, scope: !12)
// CHECK:STDOUT: !14 = !DILocation(line: 11, column: 1, scope: !12)
// CHECK:STDOUT: !15 = distinct !DISubprogram(name: "TestSDiv", linkageName: "_CTestSDiv.Main", scope: null, file: !3, line: 14, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !16 = !DILocation(line: 14, column: 32, scope: !15)
// CHECK:STDOUT: !17 = !DILocation(line: 14, column: 1, scope: !15)
// CHECK:STDOUT: !18 = distinct !DISubprogram(name: "TestSMod", linkageName: "_CTestSMod.Main", scope: null, file: !3, line: 17, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !19 = !DILocation(line: 17, column: 32, scope: !18)
// CHECK:STDOUT: !20 = !DILocation(line: 17, column: 1, scope: !18)
// CHECK:STDOUT: !21 = distinct !DISubprogram(name: "TestUAdd", linkageName: "_CTestUAdd.Main", scope: null, file: !3, line: 20, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !22 = !DILocation(line: 20, column: 32, scope: !21)
// CHECK:STDOUT: !23 = !DILocation(line: 20, column: 1, scope: !21)
// CHECK:STDOUT: !24 = distinct !DISubprogram(name: "TestUSub", linkageName: "_CTestUSub.Main", scope: null, file: !3, line: 23, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !25 = !DILocation(line: 23, column: 32, scope: !24)
// CHECK:STDOUT: !26 = !DILocation(line: 23, column: 1, scope: !24)
// CHECK:STDOUT: !27 = distinct !DISubprogram(name: "TestUMul", linkageName: "_CTestUMul.Main", scope: null, file: !3, line: 26, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !28 = !DILocation(line: 26, column: 32, scope: !27)
// CHECK:STDOUT: !29 = !DILocation(line: 26, column: 1, scope: !27)
// CHECK:STDOUT: !30 = distinct !DISubprogram(name: "TestUDiv", linkageName: "_CTestUDiv.Main", scope: null, file: !3, line: 29, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !31 = !DILocation(line: 29, column: 32, scope: !30)
// CHECK:STDOUT: !32 = !DILocation(line: 29, column: 1, scope: !30)
// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "TestUMod", linkageName: "_CTestUMod.Main", scope: null, file: !3, line: 32, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !34 = !DILocation(line: 32, column: 32, scope: !33)
// CHECK:STDOUT: !35 = !DILocation(line: 32, column: 1, scope: !33)
// CHECK:STDOUT: !36 = distinct !DISubprogram(name: "TestAnd", linkageName: "_CTestAnd.Main", scope: null, file: !3, line: 35, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !37 = !DILocation(line: 35, column: 31, scope: !36)
// CHECK:STDOUT: !38 = !DILocation(line: 35, column: 1, scope: !36)
// CHECK:STDOUT: !39 = distinct !DISubprogram(name: "TestOr", linkageName: "_CTestOr.Main", scope: null, file: !3, line: 38, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !40 = !DILocation(line: 38, column: 30, scope: !39)
// CHECK:STDOUT: !41 = !DILocation(line: 38, column: 1, scope: !39)
// CHECK:STDOUT: !42 = distinct !DISubprogram(name: "TestXor", linkageName: "_CTestXor.Main", scope: null, file: !3, line: 41, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !43 = !DILocation(line: 41, column: 31, scope: !42)
// CHECK:STDOUT: !44 = !DILocation(line: 41, column: 1, scope: !42)
// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "TestLeftShift", linkageName: "_CTestLeftShift.Main", scope: null, file: !3, line: 44, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !46 = !DILocation(line: 44, column: 37, scope: !45)
// CHECK:STDOUT: !47 = !DILocation(line: 44, column: 1, scope: !45)
// CHECK:STDOUT: !48 = distinct !DISubprogram(name: "TestArithmeticRightShift", linkageName: "_CTestArithmeticRightShift.Main", scope: null, file: !3, line: 47, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !49 = !DILocation(line: 47, column: 48, scope: !48)
// CHECK:STDOUT: !50 = !DILocation(line: 47, column: 1, scope: !48)
// CHECK:STDOUT: !51 = distinct !DISubprogram(name: "TestLogicalRightShift", linkageName: "_CTestLogicalRightShift.Main", scope: null, file: !3, line: 50, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !52 = !DILocation(line: 50, column: 45, scope: !51)
// CHECK:STDOUT: !53 = !DILocation(line: 50, column: 1, scope: !51)
// CHECK:STDOUT: ; ModuleID = 'mixed_shift.carbon'
// CHECK:STDOUT: source_filename = "mixed_shift.carbon"
// CHECK:STDOUT:
+97 -1
View File
@@ -34,6 +34,9 @@ struct ValidateState {
TypeId type_params[MaxTypeParams] = {TypeId::None, TypeId::None};
};
template <typename TypeConstraint>
auto Check(const File& sem_ir, ValidateState& state, TypeId type_id) -> bool;
// Constraint that a type is generic type parameter `I` of the builtin,
// satisfying `TypeConstraint`. See ValidateSignature for details.
template <int I, typename TypeConstraint>
@@ -63,6 +66,20 @@ struct BuiltinType {
}
};
// Constraint that a type is a pointer to another type. See ValidateSignature
// for details.
template <typename PointeeT>
struct PointerTo {
static auto Check(const File& sem_ir, ValidateState& state, TypeId type_id)
-> bool {
if (!sem_ir.types().Is<SemIR::PointerType>(type_id)) {
return false;
}
return SemIR::Check<PointeeT>(sem_ir, state,
sem_ir.GetPointeeType(type_id));
}
};
// Constraint that a type is `()`, used as the return type of builtin functions
// with no return value.
struct NoReturn {
@@ -219,6 +236,10 @@ using IntU = TypeParam<1, AnyInt>;
// generic type parameter that is constrained to be a sized integer type.
using SizedIntT = TypeParam<0, AnySizedInt>;
// Convenience name used in the builtin type signatures below for a second
// generic type parameter that is constrained to be a sized integer type.
using SizedIntU = TypeParam<1, AnySizedInt>;
// Convenience name used in the builtin type signatures below for a first
// generic type parameter that is constrained to be an float type.
using FloatT = TypeParam<0, AnyFloat>;
@@ -337,10 +358,85 @@ constexpr BuiltinInfo IntXor = {"int.xor",
constexpr BuiltinInfo IntLeftShift = {
"int.left_shift", ValidateSignature<auto(IntT, IntU)->IntT>};
// "int.left_shift": integer right shift.
// "int.right_shift": integer right shift.
constexpr BuiltinInfo IntRightShift = {
"int.right_shift", ValidateSignature<auto(IntT, IntU)->IntT>};
// "int.sadd_assign": integer in-place addition.
constexpr BuiltinInfo IntSAddAssign = {
"int.sadd_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.ssub_assign": integer in-place subtraction.
constexpr BuiltinInfo IntSSubAssign = {
"int.ssub_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.smul_assign": integer in-place multiplication.
constexpr BuiltinInfo IntSMulAssign = {
"int.smul_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.sdiv_assign": integer in-place division.
constexpr BuiltinInfo IntSDivAssign = {
"int.sdiv_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.smod_assign": integer in-place modulo.
constexpr BuiltinInfo IntSModAssign = {
"int.smod_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.uadd_assign": unsigned integer in-place addition.
constexpr BuiltinInfo IntUAddAssign = {
"int.uadd_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.usub_assign": unsigned integer in-place subtraction.
constexpr BuiltinInfo IntUSubAssign = {
"int.usub_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.umul_assign": unsigned integer in-place multiplication.
constexpr BuiltinInfo IntUMulAssign = {
"int.umul_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.udiv_assign": unsigned integer in-place division.
constexpr BuiltinInfo IntUDivAssign = {
"int.udiv_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.mod_assign": integer in-place modulo.
constexpr BuiltinInfo IntUModAssign = {
"int.umod_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.and_assign": integer in-place bitwise and.
constexpr BuiltinInfo IntAndAssign = {
"int.and_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.or_assign": integer in-place bitwise or.
constexpr BuiltinInfo IntOrAssign = {
"int.or_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.xor_assign": integer in-place bitwise xor.
constexpr BuiltinInfo IntXorAssign = {
"int.xor_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntT)->NoReturn>};
// "int.left_shift_assign": integer in-place left shift.
constexpr BuiltinInfo IntLeftShiftAssign = {
"int.left_shift_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntU)->NoReturn>};
// "int.right_shift_assign": integer in-place right shift.
constexpr BuiltinInfo IntRightShiftAssign = {
"int.right_shift_assign",
ValidateSignature<auto(PointerTo<SizedIntT>, SizedIntU)->NoReturn>};
// "int.eq": integer equality comparison.
constexpr BuiltinInfo IntEq = {"int.eq",
ValidateSignature<auto(IntT, IntU)->Bool>};
@@ -68,6 +68,23 @@ CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntLessEq)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntGreater)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntGreaterEq)
// Integer compound assignment.
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSAddAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSSubAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSMulAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSDivAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSModAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUAddAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUSubAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUMulAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUDivAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUModAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntAndAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntOrAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntXorAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntLeftShiftAssign)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntRightShiftAssign)
// Float arithmetic.
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatNegate)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatAdd)