mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Factor out some parts of builtin handling and add declaration checking. (#3815)
In preparation for adding more builtins, factor out the handling of builtin function kinds into separate files. Add checking for builtin function signatures. The mechanism used here is intended to provide a lot of flexibility for declaring generic builtin functions and pretty arbitrary constraints on the types of parameters of builtin functions. For now, these constraints are checked when the builtin function is declared. The hope is that this will suffice, but if not, it should be straightforward to switch to doing some of the checking on call and share logic between the checks. --------- Co-authored-by: Jon Ross-Perkins <jperkins@google.com> Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
This commit is contained in:
co-authored by
Jon Ross-Perkins
Carbon Infra Bot
parent
3763d0130a
commit
a3d77d9b74
+12
-34
@@ -5,6 +5,7 @@
|
||||
#include "toolchain/check/eval.h"
|
||||
|
||||
#include "toolchain/diagnostics/diagnostic_emitter.h"
|
||||
#include "toolchain/sem_ir/builtin_function_kind.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
@@ -286,7 +287,7 @@ static auto PerformAggregateIndex(Context& context, SemIR::Inst inst)
|
||||
}
|
||||
|
||||
static auto PerformBuiltinCall(Context& context, SemIRLocation loc,
|
||||
SemIR::Call call,
|
||||
SemIR::Call /*call*/,
|
||||
SemIR::BuiltinFunctionKind builtin_kind,
|
||||
llvm::ArrayRef<SemIR::InstId> arg_ids,
|
||||
Phase phase) -> SemIR::ConstantId {
|
||||
@@ -298,20 +299,12 @@ static auto PerformBuiltinCall(Context& context, SemIRLocation loc,
|
||||
if (phase != Phase::Template) {
|
||||
break;
|
||||
}
|
||||
if (arg_ids.size() != 2) {
|
||||
break;
|
||||
}
|
||||
auto lhs = context.insts().TryGetAs<SemIR::IntLiteral>(arg_ids[0]);
|
||||
auto rhs = context.insts().TryGetAs<SemIR::IntLiteral>(arg_ids[1]);
|
||||
// TODO: Move type checking to the point where we make the call.
|
||||
if (!lhs || !rhs || lhs->type_id != rhs->type_id ||
|
||||
call.type_id != lhs->type_id) {
|
||||
break;
|
||||
}
|
||||
auto lhs = context.insts().GetAs<SemIR::IntLiteral>(arg_ids[0]);
|
||||
auto rhs = context.insts().GetAs<SemIR::IntLiteral>(arg_ids[1]);
|
||||
// TODO: Integer values should be stored in the correct bit width for
|
||||
// their types. For now we assume i32.
|
||||
auto lhs_val = context.ints().Get(lhs->int_id).sextOrTrunc(32);
|
||||
auto rhs_val = context.ints().Get(rhs->int_id).sextOrTrunc(32);
|
||||
auto lhs_val = context.ints().Get(lhs.int_id).sextOrTrunc(32);
|
||||
auto rhs_val = context.ints().Get(rhs.int_id).sextOrTrunc(32);
|
||||
bool overflow = false;
|
||||
auto result = context.ints().Add(lhs_val.sadd_ov(rhs_val, overflow));
|
||||
if (overflow) {
|
||||
@@ -322,28 +315,14 @@ static auto PerformBuiltinCall(Context& context, SemIRLocation loc,
|
||||
llvm::APSInt(lhs_val, false),
|
||||
llvm::APSInt(rhs_val, false));
|
||||
}
|
||||
return MakeConstantResult(context,
|
||||
SemIR::IntLiteral{lhs->type_id, result}, phase);
|
||||
return MakeConstantResult(context, SemIR::IntLiteral{lhs.type_id, result},
|
||||
phase);
|
||||
}
|
||||
}
|
||||
|
||||
return SemIR::ConstantId::NotConstant;
|
||||
}
|
||||
|
||||
// Extracts the callee function from a callee constant. Returns
|
||||
// FunctionId::Invalid if the callee is not known.
|
||||
static auto GetCalleeFunctionId(Context& context, SemIR::InstId callee_id)
|
||||
-> SemIR::FunctionId {
|
||||
if (auto bound_method =
|
||||
context.insts().TryGetAs<SemIR::BoundMethod>(callee_id)) {
|
||||
callee_id = bound_method->function_id;
|
||||
}
|
||||
if (auto callee = context.insts().TryGetAs<SemIR::FunctionDecl>(callee_id)) {
|
||||
return {callee->function_id};
|
||||
}
|
||||
return {SemIR::FunctionId::Invalid};
|
||||
}
|
||||
|
||||
static auto PerformCall(Context& context, SemIRLocation loc, SemIR::Call call)
|
||||
-> SemIR::ConstantId {
|
||||
Phase phase = Phase::Template;
|
||||
@@ -362,11 +341,10 @@ static auto PerformCall(Context& context, SemIRLocation loc, SemIR::Call call)
|
||||
return SemIR::ConstantId::NotConstant;
|
||||
}
|
||||
|
||||
auto function_id = GetCalleeFunctionId(context, call.callee_id);
|
||||
|
||||
// Handle calls to builtins.
|
||||
auto& function = context.functions().Get(function_id);
|
||||
if (function.builtin_kind != SemIR::BuiltinFunctionKind::None) {
|
||||
if (auto builtin_function_kind = SemIR::BuiltinFunctionKind::ForCallee(
|
||||
context.sem_ir(), call.callee_id);
|
||||
builtin_function_kind != SemIR::BuiltinFunctionKind::None) {
|
||||
if (!ReplaceFieldWithConstantValue(context, &call, &SemIR::Call::args_id,
|
||||
&phase)) {
|
||||
return SemIR::ConstantId::NotConstant;
|
||||
@@ -374,7 +352,7 @@ static auto PerformCall(Context& context, SemIRLocation loc, SemIR::Call call)
|
||||
if (phase == Phase::UnknownDueToError) {
|
||||
return SemIR::ConstantId::Error;
|
||||
}
|
||||
return PerformBuiltinCall(context, loc, call, function.builtin_kind,
|
||||
return PerformBuiltinCall(context, loc, call, builtin_function_kind,
|
||||
context.inst_blocks().Get(call.args_id), phase);
|
||||
}
|
||||
return SemIR::ConstantId::NotConstant;
|
||||
|
||||
Reference in New Issue
Block a user