Skip to content

Commit

Permalink
Add a basic Core.Print function for ints. (#4078)
Browse files Browse the repository at this point in the history
We'd been discussing that explorer remains necessary for print, and I
was wondering if this kind of approach would be okay (we _probably_ want
this to work, based on #2110, albeit with more overloads -- but I don't
think there's a good way to support overloads at the moment).

```
╚╡../bazel-bin/examples/sieve
2
3
5
7
11
13
17
19
23
29
31
37
41
43
...
```
  • Loading branch information
jonmeow authored Jun 25, 2024
1 parent 734b54e commit 8bb80d8
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 2 deletions.
4 changes: 4 additions & 0 deletions core/prelude.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ 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";
1 change: 1 addition & 0 deletions examples/sieve.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ fn Run() -> i32 {
while (n < 1000) {
if (s.is_prime[n]) {
++number_of_primes;
Core.Print(n);
s.MarkMultiplesNotPrime(n);
}
++n;
Expand Down
6 changes: 6 additions & 0 deletions toolchain/check/eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "toolchain/sem_ir/builtin_function_kind.h"
#include "toolchain/sem_ir/function.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/inst_kind.h"
#include "toolchain/sem_ir/typed_insts.h"

namespace Carbon::Check {
Expand Down Expand Up @@ -709,6 +710,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.
return SemIR::ConstantId::NotConstant;
}

case SemIR::BuiltinFunctionKind::IntMakeType32: {
return context.constant_values().Get(SemIR::InstId::BuiltinIntType);
}
Expand Down
71 changes: 71 additions & 0 deletions toolchain/check/testdata/builtins/print.carbon
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// 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.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/print.carbon

fn Print(a: i32) = "print.int";

fn Main() {
Print(1);

Core.Print(2);
}

// CHECK:STDOUT: --- print.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template]
// CHECK:STDOUT: %.1: type = tuple_type () [template]
// CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template]
// CHECK:STDOUT: %Print.type.1: type = fn_type @Print.1 [template]
// CHECK:STDOUT: %Print.1: %Print.type.1 = struct_value () [template]
// CHECK:STDOUT: %Main.type: type = fn_type @Main [template]
// CHECK:STDOUT: %Main: %Main.type = struct_value () [template]
// CHECK:STDOUT: %.2: i32 = int_literal 1 [template]
// CHECK:STDOUT: %Print.type.2: type = fn_type @Print.2 [template]
// CHECK:STDOUT: %Print.2: %Print.type.2 = struct_value () [template]
// CHECK:STDOUT: %.3: i32 = int_literal 2 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Print = %Print.decl
// CHECK:STDOUT: .Main = %Main.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %import_ref.1: %Int32.type = import_ref ir3, inst+3, loaded [template = constants.%Int32]
// CHECK:STDOUT: %Print.decl: %Print.type.1 = fn_decl @Print.1 [template = constants.%Print.1] {
// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32]
// CHECK:STDOUT: %.loc11_13.1: type = value_of_initializer %int.make_type_32 [template = i32]
// CHECK:STDOUT: %.loc11_13.2: type = converted %int.make_type_32, %.loc11_13.1 [template = i32]
// CHECK:STDOUT: %a.loc11_10.1: i32 = param a
// CHECK:STDOUT: @Print.1.%a: i32 = bind_name a, %a.loc11_10.1
// CHECK:STDOUT: }
// CHECK:STDOUT: %Main.decl: %Main.type = fn_decl @Main [template = constants.%Main] {}
// CHECK:STDOUT: %import_ref.2: %Print.type.2 = import_ref ir1, inst+42, loaded [template = constants.%Print.2]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Print.1(%a: i32) = "print.int";
// 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: %.loc14: i32 = int_literal 1 [template = constants.%.2]
// CHECK:STDOUT: %print.int.loc14: init %.1 = call %Print.ref.loc14(%.loc14)
// CHECK:STDOUT: %Core.ref: <namespace> = name_ref Core, file.%Core [template = file.%Core]
// CHECK:STDOUT: %Print.ref.loc16: %Print.type.2 = name_ref Print, file.%import_ref.2 [template = constants.%Print.2]
// CHECK:STDOUT: %.loc16: i32 = int_literal 2 [template = constants.%.3]
// CHECK:STDOUT: %print.int.loc16: init %.1 = call %Print.ref.loc16(%.loc16)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Print.2(%x: i32) = "print.int";
// CHECK:STDOUT:
3 changes: 1 addition & 2 deletions toolchain/codegen/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@ auto CodeGen::Make(llvm::Module& module, llvm::StringRef target_triple,
constexpr llvm::StringLiteral Features = "";

llvm::TargetOptions target_opts;
std::optional<llvm::Reloc::Model> reloc_model;
CodeGen codegen(module, errors);
codegen.target_machine_.reset(target->createTargetMachine(
target_triple, CPU, Features, target_opts, reloc_model));
target_triple, CPU, Features, target_opts, llvm::Reloc::PIC_));
return codegen;
}

Expand Down
17 changes: 17 additions & 0 deletions toolchain/lower/handle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,23 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id,
case SemIR::BuiltinFunctionKind::None:
CARBON_FATAL() << "No callee in function call.";

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 =
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"));
return;
}

case SemIR::BuiltinFunctionKind::BoolMakeType:
case SemIR::BuiltinFunctionKind::FloatMakeType:
case SemIR::BuiltinFunctionKind::IntMakeType32:
Expand Down
26 changes: 26 additions & 0 deletions toolchain/lower/testdata/builtins/print.carbon
Original file line number Diff line number Diff line change
@@ -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
//
// 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 @Main() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %print.int.printf = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 1)
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: declare i32 @printf(ptr, ...)
16 changes: 16 additions & 0 deletions toolchain/sem_ir/builtin_function_kind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ struct BuiltinType {
}
};

// Constraint that the function has no return.
struct NoReturn {
static auto Check(const File& sem_ir, ValidateState& /*state*/,
TypeId type_id) -> bool {
auto tuple = sem_ir.types().TryGetAs<SemIR::TupleType>(type_id);
if (!tuple) {
return false;
}
return sem_ir.type_blocks().Get(tuple->elements_id).empty();
}
};

// Constraint that a type is `bool`.
using Bool = BuiltinType<InstId::BuiltinBoolType>;

Expand Down Expand Up @@ -157,6 +169,10 @@ using FloatT = TypeParam<0, AnyFloat>;
// Not a builtin function.
constexpr BuiltinInfo None = {"", nullptr};

// Prints an argument.
constexpr BuiltinInfo PrintInt = {"print.int",
ValidateSignature<auto(AnyInt)->NoReturn>};

// Returns the `i32` type. Doesn't take a bit size because we need an integer
// type as a basis for that.
constexpr BuiltinInfo IntMakeType32 = {"int.make_type_32",
Expand Down
1 change: 1 addition & 0 deletions toolchain/sem_ir/builtin_function_kind.def
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#endif

CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(None)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(PrintInt)

// Type factories.
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntMakeType32)
Expand Down

0 comments on commit 8bb80d8

Please sign in to comment.