Add solutions for advent of code 2024 day 1 to examples/. (#4673)

In order to support these examples, this adds two new builtins to the
toolchain: `print.char` and `read.char`, which map to the libc functions
`putchar` and `getchar`.
This commit is contained in:
Richard Smith
2024-12-17 00:47:51 +00:00
committed by GitHub
parent b25117b508
commit 3645143e27
20 changed files with 620 additions and 80 deletions
+2 -1
View File
@@ -5,9 +5,10 @@
load("//bazel/manifest:defs.bzl", "manifest")
# Raw prelude files.
# TODO: This includes all of Core, not just the prelude.
filegroup(
name = "prelude_files",
srcs = ["prelude.carbon"] + glob(["prelude/**/*.carbon"]),
srcs = glob(["**/*.carbon"]),
visibility = ["//visibility:public"],
)
+19
View File
@@ -0,0 +1,19 @@
// 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
//
// AUTOUPDATE
package Core library "io";
import library "prelude";
// TODO: Support printing other types.
// TODO: Consider rewriting using native support once library support exists.
fn Print(x: i32) = "print.int";
fn PrintChar(x: i32) -> i32 = "print.char";
fn ReadChar() -> i32 = "read.char";
// TODO: Change this to a global constant once they are fully supported.
// TODO: Use simply -1 once we support negate on an IntLiteral.
fn EOF() -> i32 { return -(1 as i32); }
-4
View File
@@ -8,7 +8,3 @@ package Core library "prelude";
export import library "prelude/operators";
export import library "prelude/types";
// TODO: Support printing other types.
// TODO: Consider rewriting using native support once library support exists.
fn Print(x: i32) = "print.int";
+26
View File
@@ -0,0 +1,26 @@
# 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
load("//bazel/carbon_rules:defs.bzl", "carbon_binary")
utils = [
"io_utils.carbon",
"sort.carbon",
]
carbon_binary(
name = "day1_part1",
srcs = [
"day1_common.carbon",
"day1_part1.carbon",
] + utils,
)
carbon_binary(
name = "day1_part2",
srcs = [
"day1_common.carbon",
"day1_part2.carbon",
] + utils,
)
+17
View File
@@ -0,0 +1,17 @@
# Advent of Code 2024
<!--
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
-->
This directory contains sample solutions written in Carbon for
[Advent of Code 2024](https://adventofcode.com/2024/).
The Carbon toolchain is in a very early state, so these samples frequently need
to work around missing functionality and are not reflective of expected Carbon
style and idioms. Instead, the purpose of these examples are to test the current
state of the toolchain against larger code examples than those that are present
in the toolchain's own tests, to find bugs in the toolchain, and to drive
feature development in the toolchain by presenting somewhat realistic testcases.
+21
View File
@@ -0,0 +1,21 @@
// 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
library "day1_common";
import library "io_utils";
// Read a sequence of lines each containing a pair of numbers into two arrays.
// Returns the number of lines read.
fn ReadInputs(ap: [i32; 1000]*, bp: [i32; 1000]*) -> i32 {
var n: i32 = 0;
var a: i32;
var b: i32;
while (n < 1000 and ReadInt(&a) and SkipSpaces() and ReadInt(&b) and SkipNewline()) {
(*ap)[n] = a;
(*bp)[n] = b;
++n;
}
return n;
}
+26
View File
@@ -0,0 +1,26 @@
// 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
import Core library "io";
import library "day1_common";
import library "sort";
fn Abs(n: i32) -> i32 { return if n < 0 then -n else n; }
fn Run() {
var a: [i32; 1000];
var b: [i32; 1000];
var n: i32 = ReadInputs(&a, &b);
Quicksort(&a, 0, n);
Quicksort(&b, 0, n);
var i: i32 = 0;
var difference: i32 = 0;
while (i < n) {
difference += Abs(a[i] - b[i]);
i += 1;
}
Core.Print(difference);
}
+31
View File
@@ -0,0 +1,31 @@
// 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
import Core library "io";
import library "day1_common";
import library "sort";
fn Run() {
var a: [i32; 1000];
var b: [i32; 1000];
var n: i32 = ReadInputs(&a, &b);
Quicksort(&a, 0, n);
Quicksort(&b, 0, n);
var i: i32 = 0;
var j: i32 = 0;
var similarity: i32 = 0;
while (i < n and j < n) {
if (a[i] < b[j]) {
++i;
} else {
if (a[i] == b[j]) {
similarity += b[j];
}
++j;
}
}
Core.Print(similarity);
}
+73
View File
@@ -0,0 +1,73 @@
// 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
library "io_utils";
import Core library "io";
// TODO: Use Core.EOF() rather than 0 as a sentinel here.
// At the moment, 0 is the only value we can initialize a global to,
// so we store the value plus 1 here.
var push_back: i32 = 0;
fn ReadChar() -> i32 {
var next: i32 = push_back - 1;
push_back = 0;
// TODO: assert(push_back == Core.EOF());
if (next == Core.EOF()) {
next = Core.ReadChar();
}
return next;
}
fn UnreadChar(c: i32) {
// TODO: assert(push_back == Core.EOF());
push_back = c + 1;
}
fn ReadInt(p: i32*) -> bool {
var read_any_digits: bool = false;
*p = 0;
while (true) {
var c: i32 = ReadChar();
if (c < 0x30 or c > 0x39) {
UnreadChar(c);
break;
}
// TODO: Check for overflow.
*p *= 10;
*p += c - 0x30;
read_any_digits = true;
}
return read_any_digits;
}
fn SkipSpaces() -> bool {
var skipped_any_spaces: bool = false;
while (true) {
var c: i32 = ReadChar();
if (c != 0x20) {
UnreadChar(c);
break;
}
skipped_any_spaces = true;
}
return skipped_any_spaces;
}
fn SkipNewline() -> bool {
var c: i32 = ReadChar();
// Optional carriage return.
if (c == 0x0D) {
c = ReadChar();
}
// Newline.
if (c == 0x0A) {
return true;
}
// TODO: Unread the CR?
UnreadChar(c);
return false;
}
+43
View File
@@ -0,0 +1,43 @@
// 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
library "sort";
// TODO: Generalize this for other container types once we implement lowering
// for generic functions.
fn Swap(p: [i32; 1000]*, from: i32, to: i32) {
var tmp: i32 = (*p)[from];
(*p)[from] = (*p)[to];
(*p)[to] = tmp;
}
fn Partition(p: [i32; 1000]*, from_in: i32, to_in: i32) -> i32 {
var pivot_index: i32 = from_in;
var pivot: i32 = (*p)[pivot_index];
var from: i32 = from_in + 1;
var to: i32 = to_in;
while (from < to) {
if ((*p)[from] <= pivot) {
++from;
} else if ((*p)[to - 1] > pivot) {
--to;
} else {
// Element at `from` is > pivot, and
// element at `to` is <= pivot.
Swap(p, from, to - 1);
++from;
--to;
}
}
Swap(p, pivot_index, from - 1);
return from - 1;
}
fn Quicksort(p: [i32; 1000]*, from: i32, to: i32) {
if (from + 1 >= to) { return; }
var pivot: i32 = Partition(p, from, to);
Quicksort(p, from, pivot);
Quicksort(p, pivot + 1, to);
}
+2
View File
@@ -2,6 +2,8 @@
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
import Core library "io";
// Compute and return the number of primes less than 1000.
class Sieve {
+5 -2
View File
@@ -1107,8 +1107,11 @@ static auto MakeConstantForBuiltinCall(Context& context, SemIRLoc loc,
case SemIR::BuiltinFunctionKind::None:
CARBON_FATAL("Not a builtin function.");
case SemIR::BuiltinFunctionKind::PrintInt: {
// Providing a constant result would allow eliding the function call.
case SemIR::BuiltinFunctionKind::PrintChar:
case SemIR::BuiltinFunctionKind::PrintInt:
case SemIR::BuiltinFunctionKind::ReadChar: {
// These are runtime-only builtins.
// TODO: Consider tracking this on the `BuiltinFunctionKind`.
return SemIR::ConstantId::NotConstant;
}
+107
View File
@@ -0,0 +1,107 @@
// 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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/print/char.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/print/char.carbon
import Core library "io";
fn PrintChar(a: i32) -> i32 = "print.char";
fn Main() {
PrintChar(1);
Core.PrintChar(2);
}
// CHECK:STDOUT: --- char.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template]
// CHECK:STDOUT: %PrintChar.type.1: type = fn_type @PrintChar.1 [template]
// CHECK:STDOUT: %PrintChar.1: %PrintChar.type.1 = struct_value () [template]
// CHECK:STDOUT: %Main.type: type = fn_type @Main [template]
// CHECK:STDOUT: %Main: %Main.type = struct_value () [template]
// CHECK:STDOUT: %int_1.1: Core.IntLiteral = int_value 1 [template]
// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
// CHECK:STDOUT: %Convert.type.10: type = fn_type @Convert.2, @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.10: %Convert.type.10 = struct_value () [template]
// CHECK:STDOUT: %interface.5: <witness> = interface_witness (%Convert.10) [template]
// CHECK:STDOUT: %Convert.bound.1: <bound method> = bound_method %int_1.1, %Convert.10 [template]
// CHECK:STDOUT: %Convert.specific_fn.1: <specific function> = specific_function %Convert.bound.1, @Convert.2(%int_32) [template]
// CHECK:STDOUT: %int_1.2: %i32 = int_value 1 [template]
// CHECK:STDOUT: %PrintChar.type.2: type = fn_type @PrintChar.2 [template]
// CHECK:STDOUT: %PrintChar.2: %PrintChar.type.2 = struct_value () [template]
// CHECK:STDOUT: %int_2.1: Core.IntLiteral = int_value 2 [template]
// CHECK:STDOUT: %Convert.bound.2: <bound method> = bound_method %int_2.1, %Convert.10 [template]
// CHECK:STDOUT: %Convert.specific_fn.2: <specific function> = specific_function %Convert.bound.2, @Convert.2(%int_32) [template]
// CHECK:STDOUT: %int_2.2: %i32 = int_value 2 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [template] {
// CHECK:STDOUT: .Int = %import_ref.1
// CHECK:STDOUT: .ImplicitAs = %import_ref.5
// CHECK:STDOUT: .PrintChar = %import_ref.193
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//io
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.193: %PrintChar.type.2 = import_ref Core//io, PrintChar, loaded [template = constants.%PrintChar.2]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = imports.%Core
// CHECK:STDOUT: .PrintChar = %PrintChar.decl
// CHECK:STDOUT: .Main = %Main.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %PrintChar.decl: %PrintChar.type.1 = fn_decl @PrintChar.1 [template = constants.%PrintChar.1] {
// CHECK:STDOUT: %a.patt: %i32 = binding_pattern a
// CHECK:STDOUT: %a.param_patt: %i32 = value_param_pattern %a.patt, runtime_param0
// CHECK:STDOUT: %return.patt: %i32 = return_slot_pattern
// CHECK:STDOUT: %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param1
// CHECK:STDOUT: } {
// CHECK:STDOUT: %int_32.loc13_17: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc13_17: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %int_32.loc13_25: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc13_25: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %a.param: %i32 = value_param runtime_param0
// CHECK:STDOUT: %a: %i32 = bind_name a, %a.param
// CHECK:STDOUT: %return.param: ref %i32 = out_param runtime_param1
// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %Main.decl: %Main.type = fn_decl @Main [template = constants.%Main] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @PrintChar.1(%a.param_patt: %i32) -> %i32 = "print.char";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Main() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %PrintChar.ref.loc16: %PrintChar.type.1 = name_ref PrintChar, file.%PrintChar.decl [template = constants.%PrintChar.1]
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [template = constants.%int_1.1]
// CHECK:STDOUT: %impl.elem0.loc16: %Convert.type.2 = interface_witness_access constants.%interface.5, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %Convert.bound.loc16: <bound method> = bound_method %int_1, %impl.elem0.loc16 [template = constants.%Convert.bound.1]
// CHECK:STDOUT: %Convert.specific_fn.loc16: <specific function> = specific_function %Convert.bound.loc16, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn.1]
// CHECK:STDOUT: %int.convert_checked.loc16: init %i32 = call %Convert.specific_fn.loc16(%int_1) [template = constants.%int_1.2]
// CHECK:STDOUT: %.loc16_13.1: %i32 = value_of_initializer %int.convert_checked.loc16 [template = constants.%int_1.2]
// CHECK:STDOUT: %.loc16_13.2: %i32 = converted %int_1, %.loc16_13.1 [template = constants.%int_1.2]
// CHECK:STDOUT: %print.char.loc16: init %i32 = call %PrintChar.ref.loc16(%.loc16_13.2)
// CHECK:STDOUT: %Core.ref: <namespace> = name_ref Core, imports.%Core [template = imports.%Core]
// CHECK:STDOUT: %PrintChar.ref.loc17: %PrintChar.type.2 = name_ref PrintChar, imports.%import_ref.193 [template = constants.%PrintChar.2]
// CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [template = constants.%int_2.1]
// CHECK:STDOUT: %impl.elem0.loc17: %Convert.type.2 = interface_witness_access constants.%interface.5, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %Convert.bound.loc17: <bound method> = bound_method %int_2, %impl.elem0.loc17 [template = constants.%Convert.bound.2]
// CHECK:STDOUT: %Convert.specific_fn.loc17: <specific function> = specific_function %Convert.bound.loc17, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn.2]
// CHECK:STDOUT: %int.convert_checked.loc17: init %i32 = call %Convert.specific_fn.loc17(%int_2) [template = constants.%int_2.2]
// CHECK:STDOUT: %.loc17_18.1: %i32 = value_of_initializer %int.convert_checked.loc17 [template = constants.%int_2.2]
// CHECK:STDOUT: %.loc17_18.2: %i32 = converted %int_2, %.loc17_18.1 [template = constants.%int_2.2]
// CHECK:STDOUT: %print.char.loc17: init %i32 = call %PrintChar.ref.loc17(%.loc17_18.2)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -4,9 +4,11 @@
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/print.carbon
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/print/int.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/print.carbon
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/print/int.carbon
import Core library "io";
fn Print(a: i32) = "print.int";
@@ -16,7 +18,7 @@ fn Main() {
Core.Print(2);
}
// CHECK:STDOUT: --- print.carbon
// CHECK:STDOUT: --- int.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template]
@@ -48,9 +50,10 @@ fn Main() {
// CHECK:STDOUT: .ImplicitAs = %import_ref.5
// CHECK:STDOUT: .Print = %import_ref.193
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//io
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.193: %Print.type.2 = import_ref Core//prelude, Print, loaded [template = constants.%Print.2]
// CHECK:STDOUT: %import_ref.193: %Print.type.2 = import_ref Core//io, Print, loaded [template = constants.%Print.2]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -76,25 +79,25 @@ fn Main() {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Main() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Print.ref.loc14: %Print.type.1 = name_ref Print, file.%Print.decl [template = constants.%Print.1]
// CHECK:STDOUT: %Print.ref.loc16: %Print.type.1 = name_ref Print, file.%Print.decl [template = constants.%Print.1]
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [template = constants.%int_1.1]
// CHECK:STDOUT: %impl.elem0.loc14: %Convert.type.2 = interface_witness_access constants.%interface.5, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %Convert.bound.loc14: <bound method> = bound_method %int_1, %impl.elem0.loc14 [template = constants.%Convert.bound.1]
// CHECK:STDOUT: %Convert.specific_fn.loc14: <specific function> = specific_function %Convert.bound.loc14, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn.1]
// CHECK:STDOUT: %int.convert_checked.loc14: init %i32 = call %Convert.specific_fn.loc14(%int_1) [template = constants.%int_1.2]
// CHECK:STDOUT: %.loc14_9.1: %i32 = value_of_initializer %int.convert_checked.loc14 [template = constants.%int_1.2]
// CHECK:STDOUT: %.loc14_9.2: %i32 = converted %int_1, %.loc14_9.1 [template = constants.%int_1.2]
// CHECK:STDOUT: %print.int.loc14: init %empty_tuple.type = call %Print.ref.loc14(%.loc14_9.2)
// CHECK:STDOUT: %Core.ref: <namespace> = name_ref Core, imports.%Core [template = imports.%Core]
// CHECK:STDOUT: %Print.ref.loc16: %Print.type.2 = name_ref Print, imports.%import_ref.193 [template = constants.%Print.2]
// CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [template = constants.%int_2.1]
// CHECK:STDOUT: %impl.elem0.loc16: %Convert.type.2 = interface_witness_access constants.%interface.5, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %Convert.bound.loc16: <bound method> = bound_method %int_2, %impl.elem0.loc16 [template = constants.%Convert.bound.2]
// CHECK:STDOUT: %Convert.specific_fn.loc16: <specific function> = specific_function %Convert.bound.loc16, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn.2]
// CHECK:STDOUT: %int.convert_checked.loc16: init %i32 = call %Convert.specific_fn.loc16(%int_2) [template = constants.%int_2.2]
// CHECK:STDOUT: %.loc16_14.1: %i32 = value_of_initializer %int.convert_checked.loc16 [template = constants.%int_2.2]
// CHECK:STDOUT: %.loc16_14.2: %i32 = converted %int_2, %.loc16_14.1 [template = constants.%int_2.2]
// CHECK:STDOUT: %print.int.loc16: init %empty_tuple.type = call %Print.ref.loc16(%.loc16_14.2)
// CHECK:STDOUT: %Convert.bound.loc16: <bound method> = bound_method %int_1, %impl.elem0.loc16 [template = constants.%Convert.bound.1]
// CHECK:STDOUT: %Convert.specific_fn.loc16: <specific function> = specific_function %Convert.bound.loc16, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn.1]
// CHECK:STDOUT: %int.convert_checked.loc16: init %i32 = call %Convert.specific_fn.loc16(%int_1) [template = constants.%int_1.2]
// CHECK:STDOUT: %.loc16_9.1: %i32 = value_of_initializer %int.convert_checked.loc16 [template = constants.%int_1.2]
// CHECK:STDOUT: %.loc16_9.2: %i32 = converted %int_1, %.loc16_9.1 [template = constants.%int_1.2]
// CHECK:STDOUT: %print.int.loc16: init %empty_tuple.type = call %Print.ref.loc16(%.loc16_9.2)
// CHECK:STDOUT: %Core.ref: <namespace> = name_ref Core, imports.%Core [template = imports.%Core]
// CHECK:STDOUT: %Print.ref.loc18: %Print.type.2 = name_ref Print, imports.%import_ref.193 [template = constants.%Print.2]
// CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [template = constants.%int_2.1]
// CHECK:STDOUT: %impl.elem0.loc18: %Convert.type.2 = interface_witness_access constants.%interface.5, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %Convert.bound.loc18: <bound method> = bound_method %int_2, %impl.elem0.loc18 [template = constants.%Convert.bound.2]
// CHECK:STDOUT: %Convert.specific_fn.loc18: <specific function> = specific_function %Convert.bound.loc18, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn.2]
// CHECK:STDOUT: %int.convert_checked.loc18: init %i32 = call %Convert.specific_fn.loc18(%int_2) [template = constants.%int_2.2]
// CHECK:STDOUT: %.loc18_14.1: %i32 = value_of_initializer %int.convert_checked.loc18 [template = constants.%int_2.2]
// CHECK:STDOUT: %.loc18_14.2: %i32 = converted %int_2, %.loc18_14.1 [template = constants.%int_2.2]
// CHECK:STDOUT: %print.int.loc18: init %empty_tuple.type = call %Print.ref.loc18(%.loc18_14.2)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
+84
View File
@@ -0,0 +1,84 @@
// 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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/read/int.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/read/int.carbon
import Core library "io";
fn ReadChar() -> i32 = "read.char";
fn Main() {
let n: i32 = ReadChar();
let m: i32 = Core.ReadChar();
}
// CHECK:STDOUT: --- int.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template]
// CHECK:STDOUT: %ReadChar.type.1: type = fn_type @ReadChar.1 [template]
// CHECK:STDOUT: %ReadChar.1: %ReadChar.type.1 = struct_value () [template]
// CHECK:STDOUT: %Main.type: type = fn_type @Main [template]
// CHECK:STDOUT: %Main: %Main.type = struct_value () [template]
// CHECK:STDOUT: %ReadChar.type.2: type = fn_type @ReadChar.2 [template]
// CHECK:STDOUT: %ReadChar.2: %ReadChar.type.2 = struct_value () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [template] {
// CHECK:STDOUT: .Int = %import_ref.1
// CHECK:STDOUT: .ReadChar = %import_ref.5
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//io
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.5: %ReadChar.type.2 = import_ref Core//io, ReadChar, loaded [template = constants.%ReadChar.2]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = imports.%Core
// CHECK:STDOUT: .ReadChar = %ReadChar.decl
// CHECK:STDOUT: .Main = %Main.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %ReadChar.decl: %ReadChar.type.1 = fn_decl @ReadChar.1 [template = constants.%ReadChar.1] {
// CHECK:STDOUT: %return.patt: %i32 = return_slot_pattern
// CHECK:STDOUT: %return.param_patt: %i32 = out_param_pattern %return.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %return.param: ref %i32 = out_param runtime_param0
// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %Main.decl: %Main.type = fn_decl @Main [template = constants.%Main] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @ReadChar.1() -> %i32 = "read.char";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Main() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %int_32.loc16: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc16: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %ReadChar.ref.loc16: %ReadChar.type.1 = name_ref ReadChar, file.%ReadChar.decl [template = constants.%ReadChar.1]
// CHECK:STDOUT: %read.char.loc16: init %i32 = call %ReadChar.ref.loc16()
// CHECK:STDOUT: %.loc16_26.1: %i32 = value_of_initializer %read.char.loc16
// CHECK:STDOUT: %.loc16_26.2: %i32 = converted %read.char.loc16, %.loc16_26.1
// CHECK:STDOUT: %n: %i32 = bind_name n, %.loc16_26.2
// CHECK:STDOUT: %int_32.loc17: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc17: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %Core.ref: <namespace> = name_ref Core, imports.%Core [template = imports.%Core]
// CHECK:STDOUT: %ReadChar.ref.loc17: %ReadChar.type.2 = name_ref ReadChar, imports.%import_ref.5 [template = constants.%ReadChar.2]
// CHECK:STDOUT: %read.char.loc17: init %i32 = call %ReadChar.ref.loc17()
// CHECK:STDOUT: %.loc17_31.1: %i32 = value_of_initializer %read.char.loc17
// CHECK:STDOUT: %.loc17_31.2: %i32 = converted %read.char.loc17, %.loc17_31.1
// CHECK:STDOUT: %m: %i32 = bind_name m, %.loc17_31.2
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
+39 -11
View File
@@ -76,20 +76,48 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id,
case SemIR::BuiltinFunctionKind::None:
CARBON_FATAL("No callee in function call.");
case SemIR::BuiltinFunctionKind::PrintChar: {
auto* i32_type = llvm::IntegerType::getInt32Ty(context.llvm_context());
llvm::Value* arg_value = context.builder().CreateSExtOrTrunc(
context.GetValue(arg_ids[0]), i32_type);
auto putchar = context.llvm_module().getOrInsertFunction(
"putchar", i32_type, i32_type);
auto* result = context.builder().CreateCall(putchar, {arg_value});
context.SetLocal(
inst_id,
context.builder().CreateSExtOrTrunc(
result, context.GetType(
context.sem_ir().insts().Get(inst_id).type_id())));
return;
}
case SemIR::BuiltinFunctionKind::PrintInt: {
llvm::Type* char_type[] = {llvm::PointerType::get(
llvm::Type::getInt8Ty(context.llvm_context()), 0)};
auto* printf_type = llvm::FunctionType::get(
llvm::IntegerType::getInt32Ty(context.llvm_context()),
llvm::ArrayRef<llvm::Type*>(char_type, 1), /*isVarArg=*/true);
auto callee =
auto* i32_type = llvm::IntegerType::getInt32Ty(context.llvm_context());
auto* ptr_type = llvm::PointerType::get(context.llvm_context(), 0);
auto* printf_type = llvm::FunctionType::get(i32_type, {ptr_type},
/*isVarArg=*/true);
llvm::FunctionCallee printf =
context.llvm_module().getOrInsertFunction("printf", printf_type);
llvm::SmallVector<llvm::Value*, 1> args = {
context.builder().CreateGlobalString("%d\n", "printf.int.format")};
args.push_back(context.GetValue(arg_ids[0]));
context.SetLocal(inst_id,
context.builder().CreateCall(callee, args, "printf"));
llvm::Value* format_string =
context.builder().CreateGlobalString("%d\n", "printf.int.format");
llvm::Value* arg_value = context.builder().CreateSExtOrTrunc(
context.GetValue(arg_ids[0]), i32_type);
context.SetLocal(inst_id, context.builder().CreateCall(
printf, {format_string, arg_value}));
return;
}
case SemIR::BuiltinFunctionKind::ReadChar: {
auto* i32_type = llvm::IntegerType::getInt32Ty(context.llvm_context());
auto getchar =
context.llvm_module().getOrInsertFunction("getchar", i32_type);
auto* result = context.builder().CreateCall(getchar, {});
context.SetLocal(
inst_id,
context.builder().CreateSExtOrTrunc(
result, context.GetType(
context.sem_ir().insts().Get(inst_id).type_id())));
return;
}
-39
View File
@@ -1,39 +0,0 @@
// 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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/builtins/print.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/builtins/print.carbon
fn Main() {
Core.Print(1);
}
// CHECK:STDOUT: ; ModuleID = 'print.carbon'
// CHECK:STDOUT: source_filename = "print.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: @printf.int.format = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CMain.Main() !dbg !4 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %print.int.printf = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 1), !dbg !7
// CHECK:STDOUT: ret void, !dbg !8
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: declare i32 @printf(ptr, ...)
// 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: "print.carbon", directory: "")
// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "Main", linkageName: "_CMain.Main", scope: null, file: !3, line: 11, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !5 = !DISubroutineType(types: !6)
// CHECK:STDOUT: !6 = !{}
// CHECK:STDOUT: !7 = !DILocation(line: 12, column: 3, scope: !4)
// CHECK:STDOUT: !8 = !DILocation(line: 11, column: 1, scope: !4)
+86
View File
@@ -0,0 +1,86 @@
// 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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/builtins/print_read.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/builtins/print_read.carbon
import Core library "io";
fn PrintChar(c: i8) -> i32 = "print.char";
fn ReadChar() -> i32 = "read.char";
fn Main() {
Core.Print(1);
let EOF: i32 = -(1 as i32);
while (ReadChar() != EOF) {
// "Hi"
if (PrintChar(0x48) != EOF) {
PrintChar(0x69);
}
}
}
// CHECK:STDOUT: ; ModuleID = 'print_read.carbon'
// CHECK:STDOUT: source_filename = "print_read.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: @printf.int.format = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
// CHECK:STDOUT:
// CHECK:STDOUT: define void @_CMain.Main() !dbg !4 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 1), !dbg !7
// CHECK:STDOUT: br label %while.cond, !dbg !8
// CHECK:STDOUT:
// CHECK:STDOUT: while.cond: ; preds = %if.else, %entry
// CHECK:STDOUT: %read.char = call i32 @getchar(), !dbg !9
// CHECK:STDOUT: %int.neq.loc20 = icmp ne i32 %read.char, -1, !dbg !9
// CHECK:STDOUT: br i1 %int.neq.loc20, label %while.body, label %while.done, !dbg !8
// CHECK:STDOUT:
// CHECK:STDOUT: while.body: ; preds = %while.cond
// CHECK:STDOUT: %print.char.loc22 = call i32 @putchar(i32 72), !dbg !10
// CHECK:STDOUT: %int.neq.loc22 = icmp ne i32 %print.char.loc22, -1, !dbg !10
// CHECK:STDOUT: br i1 %int.neq.loc22, label %if.then, label %if.else, !dbg !11
// CHECK:STDOUT:
// CHECK:STDOUT: if.then: ; preds = %while.body
// CHECK:STDOUT: %print.char.loc23 = call i32 @putchar(i32 105), !dbg !12
// CHECK:STDOUT: br label %if.else, !dbg !13
// CHECK:STDOUT:
// CHECK:STDOUT: if.else: ; preds = %if.then, %while.body
// CHECK:STDOUT: br label %while.cond, !dbg !14
// CHECK:STDOUT:
// CHECK:STDOUT: while.done: ; preds = %while.cond
// CHECK:STDOUT: ret void, !dbg !15
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: declare i32 @printf(ptr, ...)
// CHECK:STDOUT:
// CHECK:STDOUT: declare i32 @getchar()
// CHECK:STDOUT:
// CHECK:STDOUT: declare i32 @putchar(i32)
// CHECK:STDOUT:
// CHECK:STDOUT: ; uselistorder directives
// CHECK:STDOUT: uselistorder ptr @putchar, { 1, 0 }
// 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: "print_read.carbon", directory: "")
// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "Main", linkageName: "_CMain.Main", scope: null, file: !3, line: 16, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !5 = !DISubroutineType(types: !6)
// CHECK:STDOUT: !6 = !{}
// CHECK:STDOUT: !7 = !DILocation(line: 17, column: 3, scope: !4)
// CHECK:STDOUT: !8 = !DILocation(line: 20, column: 9, scope: !4)
// CHECK:STDOUT: !9 = !DILocation(line: 20, column: 10, scope: !4)
// CHECK:STDOUT: !10 = !DILocation(line: 22, column: 9, scope: !4)
// CHECK:STDOUT: !11 = !DILocation(line: 22, column: 8, scope: !4)
// CHECK:STDOUT: !12 = !DILocation(line: 23, column: 7, scope: !4)
// CHECK:STDOUT: !13 = !DILocation(line: 22, column: 5, scope: !4)
// CHECK:STDOUT: !14 = !DILocation(line: 20, column: 3, scope: !4)
// CHECK:STDOUT: !15 = !DILocation(line: 16, column: 1, scope: !4)
+11 -2
View File
@@ -63,7 +63,8 @@ struct BuiltinType {
}
};
// Constraint that the function has no return.
// Constraint that a type is `()`, used as the return type of builtin functions
// with no return value.
struct NoReturn {
static auto Check(const File& sem_ir, ValidateState& /*state*/,
TypeId type_id) -> bool {
@@ -194,10 +195,18 @@ using FloatT = TypeParam<0, AnyFloat>;
// Not a builtin function.
constexpr BuiltinInfo None = {"", nullptr};
// Prints an argument.
// Prints a single character.
constexpr BuiltinInfo PrintChar = {"print.char",
ValidateSignature<auto(AnyInt)->AnyInt>};
// Prints an integer.
constexpr BuiltinInfo PrintInt = {"print.int",
ValidateSignature<auto(AnyInt)->NoReturn>};
// Reads a single character from stdin.
constexpr BuiltinInfo ReadChar = {"read.char",
ValidateSignature<auto()->AnyInt>};
// Returns the `Core.IntLiteral` type.
constexpr BuiltinInfo IntLiteralMakeType = {"int_literal.make_type",
ValidateSignature<auto()->Type>};
@@ -17,7 +17,11 @@
#endif
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(None)
// Temporary builtins for primitive IO.
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(PrintChar)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(PrintInt)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(ReadChar)
// Type factories.
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntLiteralMakeType)