Add builtins for basic float operations (#3897)

Adds support for unary `-` and binary `+`, `-`, `*`, `/` for floating
point types.

Real literals are now transformed to `llvm::APFloat`s during the check
phase into the `FloatLiteral` instruction.

This PR likely collides a bit with #3892 and might need to be updated
when that one is merged.
This commit is contained in:
Pablo Paglilla
2024-04-19 22:50:54 +00:00
committed by GitHub
parent db324c7247
commit cae62765af
43 changed files with 1550 additions and 93 deletions
+16
View File
@@ -9,6 +9,7 @@
#include "common/check.h"
#include "common/ostream.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Sequence.h"
@@ -59,6 +60,18 @@ struct IntId : public IdBase, public Printable<IntId> {
};
constexpr IntId IntId::Invalid(IntId::InvalidIndex);
// Corresponds to a float value represented by an APFloat.
struct FloatId : public IdBase, public Printable<FloatId> {
using ValueType = const llvm::APFloat;
static const FloatId Invalid;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "float";
IdBase::Print(out);
}
};
constexpr FloatId FloatId::Invalid(FloatId::InvalidIndex);
// Corresponds to a Real value.
struct RealId : public IdBase, public Printable<RealId> {
using ValueType = const Real;
@@ -274,6 +287,8 @@ class SharedValueStores : public Yaml::Printable<SharedValueStores> {
auto ints() const -> const ValueStore<IntId>& { return ints_; }
auto reals() -> ValueStore<RealId>& { return reals_; }
auto reals() const -> const ValueStore<RealId>& { return reals_; }
auto floats() -> ValueStore<FloatId>& { return floats_; }
auto floats() const -> const ValueStore<FloatId>& { return floats_; }
auto string_literal_values() -> StringStoreWrapper<StringLiteralValueId>& {
return string_literal_values_;
}
@@ -300,6 +315,7 @@ class SharedValueStores : public Yaml::Printable<SharedValueStores> {
private:
ValueStore<IntId> ints_;
ValueStore<RealId> reals_;
ValueStore<FloatId> floats_;
ValueStore<StringId> strings_;
StringStoreWrapper<IdentifierId> identifiers_;
+18
View File
@@ -59,6 +59,24 @@ TEST(ValueStore, Real) {
EXPECT_THAT(real2.is_decimal, Eq(real2_copy.is_decimal));
}
TEST(ValueStore, Float) {
llvm::APFloat float1(1.0);
llvm::APFloat float2(2.0);
SharedValueStores value_stores;
FloatId id1 = value_stores.floats().Add(float1);
FloatId id2 = value_stores.floats().Add(float2);
ASSERT_TRUE(id1.is_valid());
ASSERT_TRUE(id2.is_valid());
EXPECT_THAT(id1, Not(Eq(id2)));
EXPECT_THAT(value_stores.floats().Get(id1).compare(float1),
Eq(llvm::APFloatBase::cmpEqual));
EXPECT_THAT(value_stores.floats().Get(id2).compare(float2),
Eq(llvm::APFloatBase::cmpEqual));
}
TEST(ValueStore, String) {
std::string a = "a";
std::string b = "b";
+2
View File
@@ -978,6 +978,7 @@ class TypeCompleter {
case SemIR::Converted::Kind:
case SemIR::Deref::Kind:
case SemIR::FacetTypeAccess::Kind:
case SemIR::FloatLiteral::Kind:
case SemIR::FieldDecl::Kind:
case SemIR::FunctionDecl::Kind:
case SemIR::ImplDecl::Kind:
@@ -1055,6 +1056,7 @@ class TypeCompleter {
case SemIR::AssociatedEntityType::Kind:
case SemIR::BindSymbolicName::Kind:
case SemIR::FloatType::Kind:
case SemIR::IntType::Kind:
case SemIR::PointerType::Kind:
case SemIR::UnboundElementType::Kind:
+1
View File
@@ -327,6 +327,7 @@ class Context {
}
auto ints() -> ValueStore<IntId>& { return sem_ir().ints(); }
auto reals() -> ValueStore<RealId>& { return sem_ir().reals(); }
auto floats() -> ValueStore<FloatId>& { return sem_ir().floats(); }
auto string_literal_values() -> StringStoreWrapper<StringLiteralValueId>& {
return sem_ir().string_literal_values();
}
+102
View File
@@ -91,6 +91,14 @@ static auto MakeIntResult(Context& context, SemIR::TypeId type_id,
Phase::Template);
}
// Converts an APFloat value into a ConstantId.
static auto MakeFloatResult(Context& context, SemIR::TypeId type_id,
llvm::APFloat value) -> SemIR::ConstantId {
auto result = context.floats().Add(std::move(value));
return MakeConstantResult(context, SemIR::FloatLiteral{type_id, result},
Phase::Template);
}
// `GetConstantValue` checks to see whether the provided ID describes a value
// with constant phase, and if so, returns the corresponding constant value.
// Overloads are provided for different kinds of ID.
@@ -366,6 +374,18 @@ static auto ValidateFloatBitWidth(Context& context, SemIRLoc loc,
return false;
}
// Enforces that a float type has a valid bit width.
auto ValidateFloatType(Context& context, SemIRLoc loc, SemIR::FloatType result)
-> bool {
auto bit_width =
context.insts().TryGetAs<SemIR::IntLiteral>(result.bit_width_id);
if (!bit_width) {
// Symbolic bit width.
return true;
}
return ValidateFloatBitWidth(context, loc, result.bit_width_id);
}
// Issues a diagnostic for a compile-time division by zero.
static auto DiagnoseDivisionByZero(Context& context, SemIRLoc loc) -> void {
CARBON_DIAGNOSTIC(CompileTimeDivisionByZero, Error, "Division by zero.");
@@ -578,6 +598,58 @@ static auto PerformBuiltinIntComparison(Context& context,
return MakeBoolResult(context, bool_type_id, result);
}
// Performs a builtin unary float -> float operation.
static auto PerformBuiltinUnaryFloatOp(Context& context,
SemIR::BuiltinFunctionKind builtin_kind,
SemIR::InstId arg_id)
-> SemIR::ConstantId {
auto op = context.insts().GetAs<SemIR::FloatLiteral>(arg_id);
auto op_val = context.floats().Get(op.float_id);
switch (builtin_kind) {
case SemIR::BuiltinFunctionKind::FloatNegate:
op_val.changeSign();
break;
default:
CARBON_FATAL() << "Unexpected builtin kind";
}
return MakeFloatResult(context, op.type_id, std::move(op_val));
}
// Performs a builtin binary float -> float operation.
static auto PerformBuiltinBinaryFloatOp(Context& context,
SemIR::BuiltinFunctionKind builtin_kind,
SemIR::InstId lhs_id,
SemIR::InstId rhs_id)
-> SemIR::ConstantId {
auto lhs = context.insts().GetAs<SemIR::FloatLiteral>(lhs_id);
auto rhs = context.insts().GetAs<SemIR::FloatLiteral>(rhs_id);
auto lhs_val = context.floats().Get(lhs.float_id);
auto rhs_val = context.floats().Get(rhs.float_id);
llvm::APFloat result_val(lhs_val.getSemantics());
switch (builtin_kind) {
case SemIR::BuiltinFunctionKind::FloatAdd:
result_val = lhs_val + rhs_val;
break;
case SemIR::BuiltinFunctionKind::FloatSub:
result_val = lhs_val - rhs_val;
break;
case SemIR::BuiltinFunctionKind::FloatMul:
result_val = lhs_val * rhs_val;
break;
case SemIR::BuiltinFunctionKind::FloatDiv:
result_val = lhs_val / rhs_val;
break;
default:
CARBON_FATAL() << "Unexpected operation kind.";
}
return MakeFloatResult(context, lhs.type_id, std::move(result_val));
}
static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call,
SemIR::BuiltinFunctionKind builtin_kind,
llvm::ArrayRef<SemIR::InstId> arg_ids,
@@ -661,6 +733,27 @@ static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call,
return PerformBuiltinIntComparison(context, builtin_kind, arg_ids[0],
arg_ids[1], call.type_id);
}
// Unary float -> float operations.
case SemIR::BuiltinFunctionKind::FloatNegate: {
if (phase != Phase::Template) {
break;
}
return PerformBuiltinUnaryFloatOp(context, builtin_kind, arg_ids[0]);
}
// Binary float -> float operations.
case SemIR::BuiltinFunctionKind::FloatAdd:
case SemIR::BuiltinFunctionKind::FloatSub:
case SemIR::BuiltinFunctionKind::FloatMul:
case SemIR::BuiltinFunctionKind::FloatDiv: {
if (phase != Phase::Template) {
break;
}
return PerformBuiltinBinaryFloatOp(context, builtin_kind, arg_ids[0],
arg_ids[1]);
}
}
return SemIR::ConstantId::NotConstant;
@@ -767,6 +860,14 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
case SemIR::PointerType::Kind:
return RebuildIfFieldsAreConstant(context, inst,
&SemIR::PointerType::pointee_id);
case CARBON_KIND(SemIR::FloatType float_type): {
return RebuildAndValidateIfFieldsAreConstant(
context, inst,
[&](SemIR::FloatType result) {
return ValidateFloatType(context, float_type.bit_width_id, result);
},
&SemIR::FloatType::bit_width_id);
}
case SemIR::StructType::Kind:
return RebuildIfFieldsAreConstant(context, inst,
&SemIR::StructType::fields_id);
@@ -839,6 +940,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
return SemIR::ConstantId::ForTemplateConstant(inst_id);
case SemIR::BoolLiteral::Kind:
case SemIR::FloatLiteral::Kind:
case SemIR::IntLiteral::Kind:
case SemIR::RealLiteral::Kind:
case SemIR::StringLiteral::Kind:
+38 -3
View File
@@ -58,11 +58,46 @@ auto HandleIntLiteral(Context& context, Parse::IntLiteralId node_id) -> bool {
}
auto HandleRealLiteral(Context& context, Parse::RealLiteralId node_id) -> bool {
// Convert the real literal to an llvm::APFloat and add it to the floats
// ValueStore. In the future this would use an arbitrary precision Rational
// type.
//
// TODO: Implement Carbon's actual implicit conversion rules for
// floating-point constants, as per the design
// docs/design/expressions/implicit_conversions.md
auto real_id =
context.tokens().GetRealLiteral(context.parse_tree().node_token(node_id));
auto real_value = context.sem_ir().reals().Get(real_id);
if (real_value.mantissa.getActiveBits() > 64) {
CARBON_DIAGNOSTIC(RealMantissaTooLargeForI64, Error,
"Real mantissa with value {0} does not fit in i64.",
llvm::APSInt);
context.emitter().Emit(node_id, RealMantissaTooLargeForI64,
llvm::APSInt(real_value.mantissa, true));
context.node_stack().Push(node_id, SemIR::InstId::BuiltinError);
return true;
}
if (real_value.exponent.getSignificantBits() > 64) {
CARBON_DIAGNOSTIC(RealExponentTooLargeForI64, Error,
"Real exponent with value {0} does not fit in i64.",
llvm::APSInt);
context.emitter().Emit(node_id, RealExponentTooLargeForI64,
llvm::APSInt(real_value.exponent, false));
context.node_stack().Push(node_id, SemIR::InstId::BuiltinError);
return true;
}
double double_val = real_value.mantissa.getZExtValue() *
std::pow((real_value.is_decimal ? 10 : 2),
real_value.exponent.getSExtValue());
auto float_id = context.sem_ir().floats().Add(llvm::APFloat(double_val));
context.AddInstAndPush(
{node_id,
SemIR::RealLiteral{context.GetBuiltinType(SemIR::BuiltinKind::FloatType),
context.tokens().GetRealLiteral(
context.parse_tree().node_token(node_id))}});
SemIR::FloatLiteral{
context.GetBuiltinType(SemIR::BuiltinKind::FloatType), float_id}});
return true;
}
+4 -4
View File
@@ -20,8 +20,8 @@ var c: [(); 5] = ((), (), (), (), (),);
// CHECK:STDOUT: %.7: i32 = int_literal 2 [template]
// CHECK:STDOUT: %.8: type = array_type %.7, f64 [template]
// CHECK:STDOUT: %.9: type = ptr_type [f64; 2] [template]
// CHECK:STDOUT: %.10: f64 = real_literal 111e-1 [template]
// CHECK:STDOUT: %.11: f64 = real_literal 22e-1 [template]
// CHECK:STDOUT: %.10: f64 = float_literal 11.100000000000001 [template]
// CHECK:STDOUT: %.11: f64 = float_literal 2.2000000000000002 [template]
// CHECK:STDOUT: %.12: type = tuple_type (f64, f64) [template]
// CHECK:STDOUT: %.13: [f64; 2] = tuple_value (%.10, %.11) [template]
// CHECK:STDOUT: %.14: type = tuple_type () [template]
@@ -69,8 +69,8 @@ var c: [(); 5] = ((), (), (), (), (),);
// CHECK:STDOUT: %.loc7_22.5: init [i32; 1] = array_init (%.loc7_22.4) to file.%a.var [template = constants.%.6]
// CHECK:STDOUT: %.loc7_23: init [i32; 1] = converted %.loc7_22.1, %.loc7_22.5 [template = constants.%.6]
// CHECK:STDOUT: assign file.%a.var, %.loc7_23
// CHECK:STDOUT: %.loc8_20: f64 = real_literal 111e-1 [template = constants.%.10]
// CHECK:STDOUT: %.loc8_26: f64 = real_literal 22e-1 [template = constants.%.11]
// CHECK:STDOUT: %.loc8_20: f64 = float_literal 11.100000000000001 [template = constants.%.10]
// CHECK:STDOUT: %.loc8_26: f64 = float_literal 2.2000000000000002 [template = constants.%.11]
// CHECK:STDOUT: %.loc8_30.1: (f64, f64) = tuple_literal (%.loc8_20, %.loc8_26)
// CHECK:STDOUT: %.loc8_30.2: i32 = int_literal 0 [template = constants.%.5]
// CHECK:STDOUT: %.loc8_30.3: ref f64 = array_index file.%b.var, %.loc8_30.2
+2 -2
View File
@@ -13,7 +13,7 @@ var test_type: type = i32;
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: i32 = int_literal 0 [template]
// CHECK:STDOUT: %.2: f64 = real_literal 1e-1 [template]
// CHECK:STDOUT: %.2: f64 = float_literal 0.10000000000000001 [template]
// CHECK:STDOUT: %.3: type = ptr_type String [template]
// CHECK:STDOUT: %.4: String = string_literal "Test" [template]
// CHECK:STDOUT: }
@@ -40,7 +40,7 @@ var test_type: type = i32;
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc7: i32 = int_literal 0 [template = constants.%.1]
// CHECK:STDOUT: assign file.%test_i32.var, %.loc7
// CHECK:STDOUT: %.loc8: f64 = real_literal 1e-1 [template = constants.%.2]
// CHECK:STDOUT: %.loc8: f64 = float_literal 0.10000000000000001 [template = constants.%.2]
// CHECK:STDOUT: assign file.%test_f64.var, %.loc8
// CHECK:STDOUT: assign file.%test_type.var, i32
// CHECK:STDOUT: return
@@ -16,11 +16,23 @@ let a: i32 = 39999999999999999993;
// CHECK:STDERR:
let b: i32 = 2_147_483_648;
// CHECK:STDERR: fail_numeric_literal_overflow.carbon:[[@LINE+3]]:14: ERROR: Integer literal with value 2147483648 does not fit in i32.
// CHECK:STDERR: fail_numeric_literal_overflow.carbon:[[@LINE+4]]:14: ERROR: Integer literal with value 2147483648 does not fit in i32.
// CHECK:STDERR: let c: i32 = 0x8000_0000;
// CHECK:STDERR: ^~~~~~~~~~~
// CHECK:STDERR:
let c: i32 = 0x8000_0000;
// CHECK:STDERR: fail_numeric_literal_overflow.carbon:[[@LINE+4]]:14: ERROR: Real mantissa with value 399999999999999999930 does not fit in i64.
// CHECK:STDERR: let d: f64 = 39999999999999999993.0e3;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
let d: f64 = 39999999999999999993.0e3;
// CHECK:STDERR: fail_numeric_literal_overflow.carbon:[[@LINE+3]]:14: ERROR: Real exponent with value 39999999999999999992 does not fit in i64.
// CHECK:STDERR: let e: f64 = 5.0e39999999999999999993;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
let e: f64 = 5.0e39999999999999999993;
// CHECK:STDOUT: --- fail_numeric_literal_overflow.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -31,5 +43,7 @@ let c: i32 = 0x8000_0000;
// CHECK:STDOUT: %a: i32 = bind_name a, <error>
// CHECK:STDOUT: %b: i32 = bind_name b, <error>
// CHECK:STDOUT: %c: i32 = bind_name c, <error>
// CHECK:STDOUT: %d: f64 = bind_name d, <error>
// CHECK:STDOUT: %e: f64 = bind_name e, <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
+44 -51
View File
@@ -15,14 +15,13 @@ fn F() {
2147483647,
0x7FFFFFFF,
);
var floats: [f64; 7] = (
var floats: [f64; 6] = (
0.9,
8.0,
80.0,
1.0e7,
1.0e8,
1.0e-8,
39999999999999999993.0e39999999999999999993,
1.0e-8
);
}
@@ -43,18 +42,16 @@ fn F() {
// CHECK:STDOUT: %.12: i32 = int_literal 4 [template]
// CHECK:STDOUT: %.13: i32 = int_literal 5 [template]
// CHECK:STDOUT: %.14: [i32; 6] = tuple_value (%.4, %.5, %.4, %.4, %.6, %.6) [template]
// CHECK:STDOUT: %.15: i32 = int_literal 7 [template]
// CHECK:STDOUT: %.16: type = array_type %.15, f64 [template]
// CHECK:STDOUT: %.17: type = ptr_type [f64; 7] [template]
// CHECK:STDOUT: %.18: f64 = real_literal 9e-1 [template]
// CHECK:STDOUT: %.19: f64 = real_literal 80e-1 [template]
// CHECK:STDOUT: %.20: f64 = real_literal 800e-1 [template]
// CHECK:STDOUT: %.21: f64 = real_literal 10e6 [template]
// CHECK:STDOUT: %.22: f64 = real_literal 10e7 [template]
// CHECK:STDOUT: %.23: f64 = real_literal 10e-9 [template]
// CHECK:STDOUT: %.24: f64 = real_literal 399999999999999999930e39999999999999999992 [template]
// CHECK:STDOUT: %.25: type = tuple_type (f64, f64, f64, f64, f64, f64, f64) [template]
// CHECK:STDOUT: %.26: [f64; 7] = tuple_value (%.18, %.19, %.20, %.21, %.22, %.23, %.24) [template]
// CHECK:STDOUT: %.15: type = array_type %.1, f64 [template]
// CHECK:STDOUT: %.16: type = ptr_type [f64; 6] [template]
// CHECK:STDOUT: %.17: f64 = float_literal 0.90000000000000002 [template]
// CHECK:STDOUT: %.18: f64 = float_literal 8 [template]
// CHECK:STDOUT: %.19: f64 = float_literal 80 [template]
// CHECK:STDOUT: %.20: f64 = float_literal 1.0E+7 [template]
// CHECK:STDOUT: %.21: f64 = float_literal 1.0E+8 [template]
// CHECK:STDOUT: %.22: f64 = float_literal 1.0E-8 [template]
// CHECK:STDOUT: %.23: type = tuple_type (f64, f64, f64, f64, f64, f64) [template]
// CHECK:STDOUT: %.24: [f64; 6] = tuple_value (%.17, %.18, %.19, %.20, %.21, %.22) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -100,42 +97,38 @@ fn F() {
// CHECK:STDOUT: %.loc17_3.20: init [i32; 6] = array_init (%.loc17_3.4, %.loc17_3.7, %.loc17_3.10, %.loc17_3.13, %.loc17_3.16, %.loc17_3.19) to %ints.var [template = constants.%.14]
// CHECK:STDOUT: %.loc17_4: init [i32; 6] = converted %.loc17_3.1, %.loc17_3.20 [template = constants.%.14]
// CHECK:STDOUT: assign %ints.var, %.loc17_4
// CHECK:STDOUT: %.loc18_21: i32 = int_literal 7 [template = constants.%.15]
// CHECK:STDOUT: %.loc18_22: type = array_type %.loc18_21, f64 [template = constants.%.16]
// CHECK:STDOUT: %floats.var: ref [f64; 7] = var floats
// CHECK:STDOUT: %floats: ref [f64; 7] = bind_name floats, %floats.var
// CHECK:STDOUT: %.loc19: f64 = real_literal 9e-1 [template = constants.%.18]
// CHECK:STDOUT: %.loc20: f64 = real_literal 80e-1 [template = constants.%.19]
// CHECK:STDOUT: %.loc21: f64 = real_literal 800e-1 [template = constants.%.20]
// CHECK:STDOUT: %.loc22: f64 = real_literal 10e6 [template = constants.%.21]
// CHECK:STDOUT: %.loc23: f64 = real_literal 10e7 [template = constants.%.22]
// CHECK:STDOUT: %.loc24: f64 = real_literal 10e-9 [template = constants.%.23]
// CHECK:STDOUT: %.loc25: f64 = real_literal 399999999999999999930e39999999999999999992 [template = constants.%.24]
// CHECK:STDOUT: %.loc26_3.1: (f64, f64, f64, f64, f64, f64, f64) = tuple_literal (%.loc19, %.loc20, %.loc21, %.loc22, %.loc23, %.loc24, %.loc25)
// CHECK:STDOUT: %.loc26_3.2: i32 = int_literal 0 [template = constants.%.8]
// CHECK:STDOUT: %.loc26_3.3: ref f64 = array_index %floats.var, %.loc26_3.2
// CHECK:STDOUT: %.loc26_3.4: init f64 = initialize_from %.loc19 to %.loc26_3.3 [template = constants.%.18]
// CHECK:STDOUT: %.loc26_3.5: i32 = int_literal 1 [template = constants.%.9]
// CHECK:STDOUT: %.loc26_3.6: ref f64 = array_index %floats.var, %.loc26_3.5
// CHECK:STDOUT: %.loc26_3.7: init f64 = initialize_from %.loc20 to %.loc26_3.6 [template = constants.%.19]
// CHECK:STDOUT: %.loc26_3.8: i32 = int_literal 2 [template = constants.%.10]
// CHECK:STDOUT: %.loc26_3.9: ref f64 = array_index %floats.var, %.loc26_3.8
// CHECK:STDOUT: %.loc26_3.10: init f64 = initialize_from %.loc21 to %.loc26_3.9 [template = constants.%.20]
// CHECK:STDOUT: %.loc26_3.11: i32 = int_literal 3 [template = constants.%.11]
// CHECK:STDOUT: %.loc26_3.12: ref f64 = array_index %floats.var, %.loc26_3.11
// CHECK:STDOUT: %.loc26_3.13: init f64 = initialize_from %.loc22 to %.loc26_3.12 [template = constants.%.21]
// CHECK:STDOUT: %.loc26_3.14: i32 = int_literal 4 [template = constants.%.12]
// CHECK:STDOUT: %.loc26_3.15: ref f64 = array_index %floats.var, %.loc26_3.14
// CHECK:STDOUT: %.loc26_3.16: init f64 = initialize_from %.loc23 to %.loc26_3.15 [template = constants.%.22]
// CHECK:STDOUT: %.loc26_3.17: i32 = int_literal 5 [template = constants.%.13]
// CHECK:STDOUT: %.loc26_3.18: ref f64 = array_index %floats.var, %.loc26_3.17
// CHECK:STDOUT: %.loc26_3.19: init f64 = initialize_from %.loc24 to %.loc26_3.18 [template = constants.%.23]
// CHECK:STDOUT: %.loc26_3.20: i32 = int_literal 6 [template = constants.%.1]
// CHECK:STDOUT: %.loc26_3.21: ref f64 = array_index %floats.var, %.loc26_3.20
// CHECK:STDOUT: %.loc26_3.22: init f64 = initialize_from %.loc25 to %.loc26_3.21 [template = constants.%.24]
// CHECK:STDOUT: %.loc26_3.23: init [f64; 7] = array_init (%.loc26_3.4, %.loc26_3.7, %.loc26_3.10, %.loc26_3.13, %.loc26_3.16, %.loc26_3.19, %.loc26_3.22) to %floats.var [template = constants.%.26]
// CHECK:STDOUT: %.loc26_4: init [f64; 7] = converted %.loc26_3.1, %.loc26_3.23 [template = constants.%.26]
// CHECK:STDOUT: assign %floats.var, %.loc26_4
// CHECK:STDOUT: %.loc18_21: i32 = int_literal 6 [template = constants.%.1]
// CHECK:STDOUT: %.loc18_22: type = array_type %.loc18_21, f64 [template = constants.%.15]
// CHECK:STDOUT: %floats.var: ref [f64; 6] = var floats
// CHECK:STDOUT: %floats: ref [f64; 6] = bind_name floats, %floats.var
// CHECK:STDOUT: %.loc19: f64 = float_literal 0.90000000000000002 [template = constants.%.17]
// CHECK:STDOUT: %.loc20: f64 = float_literal 8 [template = constants.%.18]
// CHECK:STDOUT: %.loc21: f64 = float_literal 80 [template = constants.%.19]
// CHECK:STDOUT: %.loc22: f64 = float_literal 1.0E+7 [template = constants.%.20]
// CHECK:STDOUT: %.loc23: f64 = float_literal 1.0E+8 [template = constants.%.21]
// CHECK:STDOUT: %.loc24: f64 = float_literal 1.0E-8 [template = constants.%.22]
// CHECK:STDOUT: %.loc25_3.1: (f64, f64, f64, f64, f64, f64) = tuple_literal (%.loc19, %.loc20, %.loc21, %.loc22, %.loc23, %.loc24)
// CHECK:STDOUT: %.loc25_3.2: i32 = int_literal 0 [template = constants.%.8]
// CHECK:STDOUT: %.loc25_3.3: ref f64 = array_index %floats.var, %.loc25_3.2
// CHECK:STDOUT: %.loc25_3.4: init f64 = initialize_from %.loc19 to %.loc25_3.3 [template = constants.%.17]
// CHECK:STDOUT: %.loc25_3.5: i32 = int_literal 1 [template = constants.%.9]
// CHECK:STDOUT: %.loc25_3.6: ref f64 = array_index %floats.var, %.loc25_3.5
// CHECK:STDOUT: %.loc25_3.7: init f64 = initialize_from %.loc20 to %.loc25_3.6 [template = constants.%.18]
// CHECK:STDOUT: %.loc25_3.8: i32 = int_literal 2 [template = constants.%.10]
// CHECK:STDOUT: %.loc25_3.9: ref f64 = array_index %floats.var, %.loc25_3.8
// CHECK:STDOUT: %.loc25_3.10: init f64 = initialize_from %.loc21 to %.loc25_3.9 [template = constants.%.19]
// CHECK:STDOUT: %.loc25_3.11: i32 = int_literal 3 [template = constants.%.11]
// CHECK:STDOUT: %.loc25_3.12: ref f64 = array_index %floats.var, %.loc25_3.11
// CHECK:STDOUT: %.loc25_3.13: init f64 = initialize_from %.loc22 to %.loc25_3.12 [template = constants.%.20]
// CHECK:STDOUT: %.loc25_3.14: i32 = int_literal 4 [template = constants.%.12]
// CHECK:STDOUT: %.loc25_3.15: ref f64 = array_index %floats.var, %.loc25_3.14
// CHECK:STDOUT: %.loc25_3.16: init f64 = initialize_from %.loc23 to %.loc25_3.15 [template = constants.%.21]
// CHECK:STDOUT: %.loc25_3.17: i32 = int_literal 5 [template = constants.%.13]
// CHECK:STDOUT: %.loc25_3.18: ref f64 = array_index %floats.var, %.loc25_3.17
// CHECK:STDOUT: %.loc25_3.19: init f64 = initialize_from %.loc24 to %.loc25_3.18 [template = constants.%.22]
// CHECK:STDOUT: %.loc25_3.20: init [f64; 6] = array_init (%.loc25_3.4, %.loc25_3.7, %.loc25_3.10, %.loc25_3.13, %.loc25_3.16, %.loc25_3.19) to %floats.var [template = constants.%.24]
// CHECK:STDOUT: %.loc25_4: init [f64; 6] = converted %.loc25_3.1, %.loc25_3.20 [template = constants.%.24]
// CHECK:STDOUT: assign %floats.var, %.loc25_4
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
+211
View File
@@ -0,0 +1,211 @@
// 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
// --- float_add.carbon
fn Add(a: f64, b: f64) -> f64 = "float.add";
fn RuntimeCall(a: f64, b: f64) -> f64 {
return Add(a, b);
}
var x: f64 = Add(2.2, 2.3);
// --- fail_bad_decl.carbon
package FailBadDecl api;
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.add".
// CHECK:STDERR: fn TooFew(a: f64) -> f64 = "float.add";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn TooFew(a: f64) -> f64 = "float.add";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.add".
// CHECK:STDERR: fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.add";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.add";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+3]]:1: ERROR: Invalid signature for builtin function "float.add".
// CHECK:STDERR: fn BadReturnType(a: f64, b: f64) -> bool = "float.add";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fn BadReturnType(a: f64, b: f64) -> bool = "float.add";
fn JustRight(a: f64, b: f64) -> f64 = "float.add";
fn RuntimeCallTooFew(a: f64) -> f64 {
return TooFew(a);
}
fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 {
return TooMany(a, b, c);
}
fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool {
return BadReturnType(a, b);
}
// CHECK:STDOUT: --- float_add.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: f64 = float_literal 2.2000000000000002 [template]
// CHECK:STDOUT: %.2: f64 = float_literal 2.3000000000000003 [template]
// CHECK:STDOUT: %.3: f64 = float_literal 4.5 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Add = %Add
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
// CHECK:STDOUT: .x = %x
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Add: <function> = fn_decl @Add [template] {
// CHECK:STDOUT: %a.loc2_8.1: f64 = param a
// CHECK:STDOUT: @Add.%a: f64 = bind_name a, %a.loc2_8.1
// CHECK:STDOUT: %b.loc2_16.1: f64 = param b
// CHECK:STDOUT: @Add.%b: f64 = bind_name b, %b.loc2_16.1
// CHECK:STDOUT: @Add.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCall: <function> = fn_decl @RuntimeCall [template] {
// CHECK:STDOUT: %a.loc4_16.1: f64 = param a
// CHECK:STDOUT: @RuntimeCall.%a: f64 = bind_name a, %a.loc4_16.1
// CHECK:STDOUT: %b.loc4_24.1: f64 = param b
// CHECK:STDOUT: @RuntimeCall.%b: f64 = bind_name b, %b.loc4_24.1
// CHECK:STDOUT: @RuntimeCall.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %x.var: ref f64 = var x
// CHECK:STDOUT: %x: ref f64 = bind_name x, %x.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Add(%a: f64, %b: f64) -> f64 = "float.add";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCall(%a: f64, %b: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Add.ref: <function> = name_ref Add, file.%Add [template = file.%Add]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %float.add: init f64 = call %Add.ref(%a.ref, %b.ref)
// CHECK:STDOUT: %.loc5_19.1: f64 = value_of_initializer %float.add
// CHECK:STDOUT: %.loc5_19.2: f64 = converted %float.add, %.loc5_19.1
// CHECK:STDOUT: return %.loc5_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Add.ref: <function> = name_ref Add, file.%Add [template = file.%Add]
// CHECK:STDOUT: %.loc8_18: f64 = float_literal 2.2000000000000002 [template = constants.%.1]
// CHECK:STDOUT: %.loc8_23: f64 = float_literal 2.3000000000000003 [template = constants.%.2]
// CHECK:STDOUT: %float.add: init f64 = call %Add.ref(%.loc8_18, %.loc8_23) [template = constants.%.3]
// CHECK:STDOUT: assign file.%x.var, %float.add
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_bad_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .TooFew = %TooFew
// CHECK:STDOUT: .TooMany = %TooMany
// CHECK:STDOUT: .BadReturnType = %BadReturnType
// CHECK:STDOUT: .JustRight = %JustRight
// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew
// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany
// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %TooFew: <function> = fn_decl @TooFew [template] {
// CHECK:STDOUT: %a.loc8_11.1: f64 = param a
// CHECK:STDOUT: @TooFew.%a: f64 = bind_name a, %a.loc8_11.1
// CHECK:STDOUT: @TooFew.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %TooMany: <function> = fn_decl @TooMany [template] {
// CHECK:STDOUT: %a.loc13_12.1: f64 = param a
// CHECK:STDOUT: @TooMany.%a: f64 = bind_name a, %a.loc13_12.1
// CHECK:STDOUT: %b.loc13_20.1: f64 = param b
// CHECK:STDOUT: @TooMany.%b: f64 = bind_name b, %b.loc13_20.1
// CHECK:STDOUT: %c.loc13_28.1: f64 = param c
// CHECK:STDOUT: @TooMany.%c: f64 = bind_name c, %c.loc13_28.1
// CHECK:STDOUT: @TooMany.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %BadReturnType: <function> = fn_decl @BadReturnType [template] {
// CHECK:STDOUT: %a.loc17_18.1: f64 = param a
// CHECK:STDOUT: @BadReturnType.%a: f64 = bind_name a, %a.loc17_18.1
// CHECK:STDOUT: %b.loc17_26.1: f64 = param b
// CHECK:STDOUT: @BadReturnType.%b: f64 = bind_name b, %b.loc17_26.1
// CHECK:STDOUT: @BadReturnType.%return: ref bool = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %JustRight: <function> = fn_decl @JustRight [template] {
// CHECK:STDOUT: %a.loc18_14.1: f64 = param a
// CHECK:STDOUT: @JustRight.%a: f64 = bind_name a, %a.loc18_14.1
// CHECK:STDOUT: %b.loc18_22.1: f64 = param b
// CHECK:STDOUT: @JustRight.%b: f64 = bind_name b, %b.loc18_22.1
// CHECK:STDOUT: @JustRight.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallTooFew: <function> = fn_decl @RuntimeCallTooFew [template] {
// CHECK:STDOUT: %a.loc20_22.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallTooFew.%a: f64 = bind_name a, %a.loc20_22.1
// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallTooMany: <function> = fn_decl @RuntimeCallTooMany [template] {
// CHECK:STDOUT: %a.loc24_23.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallTooMany.%a: f64 = bind_name a, %a.loc24_23.1
// CHECK:STDOUT: %b.loc24_31.1: f64 = param b
// CHECK:STDOUT: @RuntimeCallTooMany.%b: f64 = bind_name b, %b.loc24_31.1
// CHECK:STDOUT: %c.loc24_39.1: f64 = param c
// CHECK:STDOUT: @RuntimeCallTooMany.%c: f64 = bind_name c, %c.loc24_39.1
// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallBadReturnType: <function> = fn_decl @RuntimeCallBadReturnType [template] {
// CHECK:STDOUT: %a.loc28_29.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: f64 = bind_name a, %a.loc28_29.1
// CHECK:STDOUT: %b.loc28_37.1: f64 = param b
// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: f64 = bind_name b, %b.loc28_37.1
// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TooFew(%a: f64) -> f64;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TooMany(%a: f64, %b: f64, %c: f64) -> f64;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @BadReturnType(%a: f64, %b: f64) -> bool;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @JustRight(%a: f64, %b: f64) -> f64 = "float.add";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %TooFew.ref: <function> = name_ref TooFew, file.%TooFew [template = file.%TooFew]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %TooFew.call: init f64 = call %TooFew.ref(%a.ref)
// CHECK:STDOUT: %.loc21_19.1: f64 = value_of_initializer %TooFew.call
// CHECK:STDOUT: %.loc21_19.2: f64 = converted %TooFew.call, %.loc21_19.1
// CHECK:STDOUT: return %.loc21_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: f64, %b: f64, %c: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %TooMany.ref: <function> = name_ref TooMany, file.%TooMany [template = file.%TooMany]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %c.ref: f64 = name_ref c, %c
// CHECK:STDOUT: %TooMany.call: init f64 = call %TooMany.ref(%a.ref, %b.ref, %c.ref)
// CHECK:STDOUT: %.loc25_26.1: f64 = value_of_initializer %TooMany.call
// CHECK:STDOUT: %.loc25_26.2: f64 = converted %TooMany.call, %.loc25_26.1
// CHECK:STDOUT: return %.loc25_26.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: f64, %b: f64) -> bool {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %BadReturnType.ref: <function> = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %BadReturnType.call: init bool = call %BadReturnType.ref(%a.ref, %b.ref)
// CHECK:STDOUT: %.loc29_29.1: bool = value_of_initializer %BadReturnType.call
// CHECK:STDOUT: %.loc29_29.2: bool = converted %BadReturnType.call, %.loc29_29.1
// CHECK:STDOUT: return %.loc29_29.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
+233
View File
@@ -0,0 +1,233 @@
// 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
// --- float_div.carbon
fn Div(a: f64, b: f64) -> f64 = "float.div";
fn RuntimeCall(a: f64, b: f64) -> f64 {
return Div(a, b);
}
var a: f64 = Div(10.0, 2.5);
let b: f64 = Div(1.0, 0.0);
let c: f64 = Div(0.0, 0.0);
// --- fail_bad_decl.carbon
package FailBadDecl api;
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.div".
// CHECK:STDERR: fn TooFew(a: f64) -> f64 = "float.div";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn TooFew(a: f64) -> f64 = "float.div";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.div".
// CHECK:STDERR: fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.div";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.div";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+3]]:1: ERROR: Invalid signature for builtin function "float.div".
// CHECK:STDERR: fn BadReturnType(a: f64, b: f64) -> bool = "float.div";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fn BadReturnType(a: f64, b: f64) -> bool = "float.div";
fn JustRight(a: f64, b: f64) -> f64 = "float.div";
fn RuntimeCallTooFew(a: f64) -> f64 {
return TooFew(a);
}
fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 {
return TooMany(a, b, c);
}
fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool {
return BadReturnType(a, b);
}
// CHECK:STDOUT: --- float_div.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: f64 = float_literal 10 [template]
// CHECK:STDOUT: %.2: f64 = float_literal 2.5 [template]
// CHECK:STDOUT: %.3: f64 = float_literal 4 [template]
// CHECK:STDOUT: %.4: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.5: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.6: f64 = float_literal +Inf [template]
// CHECK:STDOUT: %.7: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.8: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.9: f64 = float_literal NaN [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Div = %Div
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
// CHECK:STDOUT: .a = %a.loc8
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Div: <function> = fn_decl @Div [template] {
// CHECK:STDOUT: %a.loc2_8.1: f64 = param a
// CHECK:STDOUT: @Div.%a: f64 = bind_name a, %a.loc2_8.1
// CHECK:STDOUT: %b.loc2_16.1: f64 = param b
// CHECK:STDOUT: @Div.%b: f64 = bind_name b, %b.loc2_16.1
// CHECK:STDOUT: @Div.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCall: <function> = fn_decl @RuntimeCall [template] {
// CHECK:STDOUT: %a.loc4_16.1: f64 = param a
// CHECK:STDOUT: @RuntimeCall.%a: f64 = bind_name a, %a.loc4_16.1
// CHECK:STDOUT: %b.loc4_24.1: f64 = param b
// CHECK:STDOUT: @RuntimeCall.%b: f64 = bind_name b, %b.loc4_24.1
// CHECK:STDOUT: @RuntimeCall.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %a.var: ref f64 = var a
// CHECK:STDOUT: %a.loc8: ref f64 = bind_name a, %a.var
// CHECK:STDOUT: %Div.ref.loc9: <function> = name_ref Div, %Div [template = %Div]
// CHECK:STDOUT: %.loc9_18: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc9_23: f64 = float_literal 0 [template = constants.%.5]
// CHECK:STDOUT: %float.div.loc9: init f64 = call %Div.ref.loc9(%.loc9_18, %.loc9_23) [template = constants.%.6]
// CHECK:STDOUT: %.loc9_27.1: f64 = value_of_initializer %float.div.loc9 [template = constants.%.6]
// CHECK:STDOUT: %.loc9_27.2: f64 = converted %float.div.loc9, %.loc9_27.1 [template = constants.%.6]
// CHECK:STDOUT: %b.loc9: f64 = bind_name b, %.loc9_27.2
// CHECK:STDOUT: %Div.ref.loc10: <function> = name_ref Div, %Div [template = %Div]
// CHECK:STDOUT: %.loc10_18: f64 = float_literal 0 [template = constants.%.7]
// CHECK:STDOUT: %.loc10_23: f64 = float_literal 0 [template = constants.%.8]
// CHECK:STDOUT: %float.div.loc10: init f64 = call %Div.ref.loc10(%.loc10_18, %.loc10_23) [template = constants.%.9]
// CHECK:STDOUT: %.loc10_27.1: f64 = value_of_initializer %float.div.loc10 [template = constants.%.9]
// CHECK:STDOUT: %.loc10_27.2: f64 = converted %float.div.loc10, %.loc10_27.1 [template = constants.%.9]
// CHECK:STDOUT: %c: f64 = bind_name c, %.loc10_27.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Div(%a: f64, %b: f64) -> f64 = "float.div";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCall(%a: f64, %b: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Div.ref: <function> = name_ref Div, file.%Div [template = file.%Div]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %float.div: init f64 = call %Div.ref(%a.ref, %b.ref)
// CHECK:STDOUT: %.loc5_19.1: f64 = value_of_initializer %float.div
// CHECK:STDOUT: %.loc5_19.2: f64 = converted %float.div, %.loc5_19.1
// CHECK:STDOUT: return %.loc5_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Div.ref: <function> = name_ref Div, file.%Div [template = file.%Div]
// CHECK:STDOUT: %.loc8_18: f64 = float_literal 10 [template = constants.%.1]
// CHECK:STDOUT: %.loc8_24: f64 = float_literal 2.5 [template = constants.%.2]
// CHECK:STDOUT: %float.div: init f64 = call %Div.ref(%.loc8_18, %.loc8_24) [template = constants.%.3]
// CHECK:STDOUT: assign file.%a.var, %float.div
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_bad_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .TooFew = %TooFew
// CHECK:STDOUT: .TooMany = %TooMany
// CHECK:STDOUT: .BadReturnType = %BadReturnType
// CHECK:STDOUT: .JustRight = %JustRight
// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew
// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany
// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %TooFew: <function> = fn_decl @TooFew [template] {
// CHECK:STDOUT: %a.loc8_11.1: f64 = param a
// CHECK:STDOUT: @TooFew.%a: f64 = bind_name a, %a.loc8_11.1
// CHECK:STDOUT: @TooFew.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %TooMany: <function> = fn_decl @TooMany [template] {
// CHECK:STDOUT: %a.loc13_12.1: f64 = param a
// CHECK:STDOUT: @TooMany.%a: f64 = bind_name a, %a.loc13_12.1
// CHECK:STDOUT: %b.loc13_20.1: f64 = param b
// CHECK:STDOUT: @TooMany.%b: f64 = bind_name b, %b.loc13_20.1
// CHECK:STDOUT: %c.loc13_28.1: f64 = param c
// CHECK:STDOUT: @TooMany.%c: f64 = bind_name c, %c.loc13_28.1
// CHECK:STDOUT: @TooMany.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %BadReturnType: <function> = fn_decl @BadReturnType [template] {
// CHECK:STDOUT: %a.loc17_18.1: f64 = param a
// CHECK:STDOUT: @BadReturnType.%a: f64 = bind_name a, %a.loc17_18.1
// CHECK:STDOUT: %b.loc17_26.1: f64 = param b
// CHECK:STDOUT: @BadReturnType.%b: f64 = bind_name b, %b.loc17_26.1
// CHECK:STDOUT: @BadReturnType.%return: ref bool = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %JustRight: <function> = fn_decl @JustRight [template] {
// CHECK:STDOUT: %a.loc18_14.1: f64 = param a
// CHECK:STDOUT: @JustRight.%a: f64 = bind_name a, %a.loc18_14.1
// CHECK:STDOUT: %b.loc18_22.1: f64 = param b
// CHECK:STDOUT: @JustRight.%b: f64 = bind_name b, %b.loc18_22.1
// CHECK:STDOUT: @JustRight.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallTooFew: <function> = fn_decl @RuntimeCallTooFew [template] {
// CHECK:STDOUT: %a.loc20_22.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallTooFew.%a: f64 = bind_name a, %a.loc20_22.1
// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallTooMany: <function> = fn_decl @RuntimeCallTooMany [template] {
// CHECK:STDOUT: %a.loc24_23.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallTooMany.%a: f64 = bind_name a, %a.loc24_23.1
// CHECK:STDOUT: %b.loc24_31.1: f64 = param b
// CHECK:STDOUT: @RuntimeCallTooMany.%b: f64 = bind_name b, %b.loc24_31.1
// CHECK:STDOUT: %c.loc24_39.1: f64 = param c
// CHECK:STDOUT: @RuntimeCallTooMany.%c: f64 = bind_name c, %c.loc24_39.1
// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallBadReturnType: <function> = fn_decl @RuntimeCallBadReturnType [template] {
// CHECK:STDOUT: %a.loc28_29.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: f64 = bind_name a, %a.loc28_29.1
// CHECK:STDOUT: %b.loc28_37.1: f64 = param b
// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: f64 = bind_name b, %b.loc28_37.1
// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TooFew(%a: f64) -> f64;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TooMany(%a: f64, %b: f64, %c: f64) -> f64;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @BadReturnType(%a: f64, %b: f64) -> bool;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @JustRight(%a: f64, %b: f64) -> f64 = "float.div";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %TooFew.ref: <function> = name_ref TooFew, file.%TooFew [template = file.%TooFew]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %TooFew.call: init f64 = call %TooFew.ref(%a.ref)
// CHECK:STDOUT: %.loc21_19.1: f64 = value_of_initializer %TooFew.call
// CHECK:STDOUT: %.loc21_19.2: f64 = converted %TooFew.call, %.loc21_19.1
// CHECK:STDOUT: return %.loc21_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: f64, %b: f64, %c: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %TooMany.ref: <function> = name_ref TooMany, file.%TooMany [template = file.%TooMany]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %c.ref: f64 = name_ref c, %c
// CHECK:STDOUT: %TooMany.call: init f64 = call %TooMany.ref(%a.ref, %b.ref, %c.ref)
// CHECK:STDOUT: %.loc25_26.1: f64 = value_of_initializer %TooMany.call
// CHECK:STDOUT: %.loc25_26.2: f64 = converted %TooMany.call, %.loc25_26.1
// CHECK:STDOUT: return %.loc25_26.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: f64, %b: f64) -> bool {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %BadReturnType.ref: <function> = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %BadReturnType.call: init bool = call %BadReturnType.ref(%a.ref, %b.ref)
// CHECK:STDOUT: %.loc29_29.1: bool = value_of_initializer %BadReturnType.call
// CHECK:STDOUT: %.loc29_29.2: bool = converted %BadReturnType.call, %.loc29_29.1
// CHECK:STDOUT: return %.loc29_29.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
+2 -2
View File
@@ -61,7 +61,7 @@ var dyn: Float(dyn_size);
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: i32 = int_literal 64 [template]
// CHECK:STDOUT: %.2: f64 = real_literal 0e-1 [template]
// CHECK:STDOUT: %.2: f64 = float_literal 0 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -101,7 +101,7 @@ var dyn: Float(dyn_size);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc6: f64 = real_literal 0e-1 [template = constants.%.2]
// CHECK:STDOUT: %.loc6: f64 = float_literal 0 [template = constants.%.2]
// CHECK:STDOUT: assign file.%f.var, %.loc6
// CHECK:STDOUT: return
// CHECK:STDOUT: }
+211
View File
@@ -0,0 +1,211 @@
// 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
// --- mul_sub.carbon
fn Mul(a: f64, b: f64) -> f64 = "float.mul";
fn RuntimeCall(a: f64, b: f64) -> f64 {
return Mul(a, b);
}
var x: f64 = Mul(2.0, 0.5);
// --- fail_bad_decl.carbon
package FailBadDecl api;
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.mul".
// CHECK:STDERR: fn TooFew(a: f64) -> f64 = "float.mul";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn TooFew(a: f64) -> f64 = "float.mul";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.mul".
// CHECK:STDERR: fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.mul";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.mul";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+3]]:1: ERROR: Invalid signature for builtin function "float.mul".
// CHECK:STDERR: fn BadReturnType(a: f64, b: f64) -> bool = "float.mul";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fn BadReturnType(a: f64, b: f64) -> bool = "float.mul";
fn JustRight(a: f64, b: f64) -> f64 = "float.mul";
fn RuntimeCallTooFew(a: f64) -> f64 {
return TooFew(a);
}
fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 {
return TooMany(a, b, c);
}
fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool {
return BadReturnType(a, b);
}
// CHECK:STDOUT: --- mul_sub.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: f64 = float_literal 2 [template]
// CHECK:STDOUT: %.2: f64 = float_literal 0.5 [template]
// CHECK:STDOUT: %.3: f64 = float_literal 1 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Mul = %Mul
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
// CHECK:STDOUT: .x = %x
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Mul: <function> = fn_decl @Mul [template] {
// CHECK:STDOUT: %a.loc2_8.1: f64 = param a
// CHECK:STDOUT: @Mul.%a: f64 = bind_name a, %a.loc2_8.1
// CHECK:STDOUT: %b.loc2_16.1: f64 = param b
// CHECK:STDOUT: @Mul.%b: f64 = bind_name b, %b.loc2_16.1
// CHECK:STDOUT: @Mul.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCall: <function> = fn_decl @RuntimeCall [template] {
// CHECK:STDOUT: %a.loc4_16.1: f64 = param a
// CHECK:STDOUT: @RuntimeCall.%a: f64 = bind_name a, %a.loc4_16.1
// CHECK:STDOUT: %b.loc4_24.1: f64 = param b
// CHECK:STDOUT: @RuntimeCall.%b: f64 = bind_name b, %b.loc4_24.1
// CHECK:STDOUT: @RuntimeCall.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %x.var: ref f64 = var x
// CHECK:STDOUT: %x: ref f64 = bind_name x, %x.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Mul(%a: f64, %b: f64) -> f64 = "float.mul";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCall(%a: f64, %b: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Mul.ref: <function> = name_ref Mul, file.%Mul [template = file.%Mul]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %float.mul: init f64 = call %Mul.ref(%a.ref, %b.ref)
// CHECK:STDOUT: %.loc5_19.1: f64 = value_of_initializer %float.mul
// CHECK:STDOUT: %.loc5_19.2: f64 = converted %float.mul, %.loc5_19.1
// CHECK:STDOUT: return %.loc5_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Mul.ref: <function> = name_ref Mul, file.%Mul [template = file.%Mul]
// CHECK:STDOUT: %.loc8_18: f64 = float_literal 2 [template = constants.%.1]
// CHECK:STDOUT: %.loc8_23: f64 = float_literal 0.5 [template = constants.%.2]
// CHECK:STDOUT: %float.mul: init f64 = call %Mul.ref(%.loc8_18, %.loc8_23) [template = constants.%.3]
// CHECK:STDOUT: assign file.%x.var, %float.mul
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_bad_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .TooFew = %TooFew
// CHECK:STDOUT: .TooMany = %TooMany
// CHECK:STDOUT: .BadReturnType = %BadReturnType
// CHECK:STDOUT: .JustRight = %JustRight
// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew
// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany
// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %TooFew: <function> = fn_decl @TooFew [template] {
// CHECK:STDOUT: %a.loc8_11.1: f64 = param a
// CHECK:STDOUT: @TooFew.%a: f64 = bind_name a, %a.loc8_11.1
// CHECK:STDOUT: @TooFew.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %TooMany: <function> = fn_decl @TooMany [template] {
// CHECK:STDOUT: %a.loc13_12.1: f64 = param a
// CHECK:STDOUT: @TooMany.%a: f64 = bind_name a, %a.loc13_12.1
// CHECK:STDOUT: %b.loc13_20.1: f64 = param b
// CHECK:STDOUT: @TooMany.%b: f64 = bind_name b, %b.loc13_20.1
// CHECK:STDOUT: %c.loc13_28.1: f64 = param c
// CHECK:STDOUT: @TooMany.%c: f64 = bind_name c, %c.loc13_28.1
// CHECK:STDOUT: @TooMany.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %BadReturnType: <function> = fn_decl @BadReturnType [template] {
// CHECK:STDOUT: %a.loc17_18.1: f64 = param a
// CHECK:STDOUT: @BadReturnType.%a: f64 = bind_name a, %a.loc17_18.1
// CHECK:STDOUT: %b.loc17_26.1: f64 = param b
// CHECK:STDOUT: @BadReturnType.%b: f64 = bind_name b, %b.loc17_26.1
// CHECK:STDOUT: @BadReturnType.%return: ref bool = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %JustRight: <function> = fn_decl @JustRight [template] {
// CHECK:STDOUT: %a.loc18_14.1: f64 = param a
// CHECK:STDOUT: @JustRight.%a: f64 = bind_name a, %a.loc18_14.1
// CHECK:STDOUT: %b.loc18_22.1: f64 = param b
// CHECK:STDOUT: @JustRight.%b: f64 = bind_name b, %b.loc18_22.1
// CHECK:STDOUT: @JustRight.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallTooFew: <function> = fn_decl @RuntimeCallTooFew [template] {
// CHECK:STDOUT: %a.loc20_22.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallTooFew.%a: f64 = bind_name a, %a.loc20_22.1
// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallTooMany: <function> = fn_decl @RuntimeCallTooMany [template] {
// CHECK:STDOUT: %a.loc24_23.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallTooMany.%a: f64 = bind_name a, %a.loc24_23.1
// CHECK:STDOUT: %b.loc24_31.1: f64 = param b
// CHECK:STDOUT: @RuntimeCallTooMany.%b: f64 = bind_name b, %b.loc24_31.1
// CHECK:STDOUT: %c.loc24_39.1: f64 = param c
// CHECK:STDOUT: @RuntimeCallTooMany.%c: f64 = bind_name c, %c.loc24_39.1
// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallBadReturnType: <function> = fn_decl @RuntimeCallBadReturnType [template] {
// CHECK:STDOUT: %a.loc28_29.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: f64 = bind_name a, %a.loc28_29.1
// CHECK:STDOUT: %b.loc28_37.1: f64 = param b
// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: f64 = bind_name b, %b.loc28_37.1
// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TooFew(%a: f64) -> f64;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TooMany(%a: f64, %b: f64, %c: f64) -> f64;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @BadReturnType(%a: f64, %b: f64) -> bool;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @JustRight(%a: f64, %b: f64) -> f64 = "float.mul";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %TooFew.ref: <function> = name_ref TooFew, file.%TooFew [template = file.%TooFew]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %TooFew.call: init f64 = call %TooFew.ref(%a.ref)
// CHECK:STDOUT: %.loc21_19.1: f64 = value_of_initializer %TooFew.call
// CHECK:STDOUT: %.loc21_19.2: f64 = converted %TooFew.call, %.loc21_19.1
// CHECK:STDOUT: return %.loc21_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: f64, %b: f64, %c: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %TooMany.ref: <function> = name_ref TooMany, file.%TooMany [template = file.%TooMany]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %c.ref: f64 = name_ref c, %c
// CHECK:STDOUT: %TooMany.call: init f64 = call %TooMany.ref(%a.ref, %b.ref, %c.ref)
// CHECK:STDOUT: %.loc25_26.1: f64 = value_of_initializer %TooMany.call
// CHECK:STDOUT: %.loc25_26.2: f64 = converted %TooMany.call, %.loc25_26.1
// CHECK:STDOUT: return %.loc25_26.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: f64, %b: f64) -> bool {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %BadReturnType.ref: <function> = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %BadReturnType.call: init bool = call %BadReturnType.ref(%a.ref, %b.ref)
// CHECK:STDOUT: %.loc29_29.1: bool = value_of_initializer %BadReturnType.call
// CHECK:STDOUT: %.loc29_29.2: bool = converted %BadReturnType.call, %.loc29_29.1
// CHECK:STDOUT: return %.loc29_29.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
+213
View File
@@ -0,0 +1,213 @@
// 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
// --- float_negate.carbon
fn Negate(a: f64) -> f64 = "float.negate";
fn RuntimeCall(a: f64, b: f64) -> f64 {
return Negate(a);
}
let a: f64 = Negate(1.5);
// --- fail_bad_decl.carbon
package FailBadDecl api;
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.negate".
// CHECK:STDERR: fn TooFew() -> f64 = "float.negate";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn TooFew() -> f64 = "float.negate";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.negate".
// CHECK:STDERR: fn TooMany(a: f64, b: f64) -> f64 = "float.negate";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn TooMany(a: f64, b: f64) -> f64 = "float.negate";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.negate".
// CHECK:STDERR: fn BadReturnType(a: f64) -> bool = "float.negate";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn BadReturnType(a: f64) -> bool = "float.negate";
fn JustRight(a: f64) -> f64 = "float.negate";
fn RuntimeCallTooFew(a: f64) -> f64 {
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: ERROR: 1 argument(s) passed to function expecting 0 argument(s).
// CHECK:STDERR: return TooFew(a);
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-17]]:1: Calling function declared here.
// CHECK:STDERR: fn TooFew() -> f64 = "float.negate";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
return TooFew(a);
}
fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 {
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: ERROR: 3 argument(s) passed to function expecting 2 argument(s).
// CHECK:STDERR: return TooMany(a, b, c);
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-23]]:1: Calling function declared here.
// CHECK:STDERR: fn TooMany(a: f64, b: f64) -> f64 = "float.negate";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
return TooMany(a, b, c);
}
fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool {
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+6]]:10: ERROR: 2 argument(s) passed to function expecting 1 argument(s).
// CHECK:STDERR: return BadReturnType(a, b);
// CHECK:STDERR: ^~~~~~~~~~~~~~
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-29]]:1: Calling function declared here.
// CHECK:STDERR: fn BadReturnType(a: f64) -> bool = "float.negate";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
return BadReturnType(a, b);
}
// CHECK:STDOUT: --- float_negate.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: f64 = float_literal 1.5 [template]
// CHECK:STDOUT: %.2: f64 = float_literal -1.5 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Negate = %Negate
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Negate: <function> = fn_decl @Negate [template] {
// CHECK:STDOUT: %a.loc2_11.1: f64 = param a
// CHECK:STDOUT: @Negate.%a: f64 = bind_name a, %a.loc2_11.1
// CHECK:STDOUT: @Negate.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCall: <function> = fn_decl @RuntimeCall [template] {
// CHECK:STDOUT: %a.loc4_16.1: f64 = param a
// CHECK:STDOUT: @RuntimeCall.%a: f64 = bind_name a, %a.loc4_16.1
// CHECK:STDOUT: %b.loc4_24.1: f64 = param b
// CHECK:STDOUT: @RuntimeCall.%b: f64 = bind_name b, %b.loc4_24.1
// CHECK:STDOUT: @RuntimeCall.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %Negate.ref: <function> = name_ref Negate, %Negate [template = %Negate]
// CHECK:STDOUT: %.loc8_21: f64 = float_literal 1.5 [template = constants.%.1]
// CHECK:STDOUT: %float.negate: init f64 = call %Negate.ref(%.loc8_21) [template = constants.%.2]
// CHECK:STDOUT: %.loc8_25.1: f64 = value_of_initializer %float.negate [template = constants.%.2]
// CHECK:STDOUT: %.loc8_25.2: f64 = converted %float.negate, %.loc8_25.1 [template = constants.%.2]
// CHECK:STDOUT: %a.loc8: f64 = bind_name a, %.loc8_25.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Negate(%a: f64) -> f64 = "float.negate";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCall(%a: f64, %b: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Negate.ref: <function> = name_ref Negate, file.%Negate [template = file.%Negate]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %float.negate: init f64 = call %Negate.ref(%a.ref)
// CHECK:STDOUT: %.loc5_19.1: f64 = value_of_initializer %float.negate
// CHECK:STDOUT: %.loc5_19.2: f64 = converted %float.negate, %.loc5_19.1
// CHECK:STDOUT: return %.loc5_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_bad_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .TooFew = %TooFew
// CHECK:STDOUT: .TooMany = %TooMany
// CHECK:STDOUT: .BadReturnType = %BadReturnType
// CHECK:STDOUT: .JustRight = %JustRight
// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew
// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany
// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %TooFew: <function> = fn_decl @TooFew [template] {
// CHECK:STDOUT: @TooFew.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %TooMany: <function> = fn_decl @TooMany [template] {
// CHECK:STDOUT: %a.loc13_12.1: f64 = param a
// CHECK:STDOUT: @TooMany.%a: f64 = bind_name a, %a.loc13_12.1
// CHECK:STDOUT: %b.loc13_20.1: f64 = param b
// CHECK:STDOUT: @TooMany.%b: f64 = bind_name b, %b.loc13_20.1
// CHECK:STDOUT: @TooMany.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %BadReturnType: <function> = fn_decl @BadReturnType [template] {
// CHECK:STDOUT: %a.loc18_18.1: f64 = param a
// CHECK:STDOUT: @BadReturnType.%a: f64 = bind_name a, %a.loc18_18.1
// CHECK:STDOUT: @BadReturnType.%return: ref bool = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %JustRight: <function> = fn_decl @JustRight [template] {
// CHECK:STDOUT: %a.loc19_14.1: f64 = param a
// CHECK:STDOUT: @JustRight.%a: f64 = bind_name a, %a.loc19_14.1
// CHECK:STDOUT: @JustRight.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallTooFew: <function> = fn_decl @RuntimeCallTooFew [template] {
// CHECK:STDOUT: %a.loc21_22.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallTooFew.%a: f64 = bind_name a, %a.loc21_22.1
// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallTooMany: <function> = fn_decl @RuntimeCallTooMany [template] {
// CHECK:STDOUT: %a.loc32_23.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallTooMany.%a: f64 = bind_name a, %a.loc32_23.1
// CHECK:STDOUT: %b.loc32_31.1: f64 = param b
// CHECK:STDOUT: @RuntimeCallTooMany.%b: f64 = bind_name b, %b.loc32_31.1
// CHECK:STDOUT: %c.loc32_39.1: f64 = param c
// CHECK:STDOUT: @RuntimeCallTooMany.%c: f64 = bind_name c, %c.loc32_39.1
// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallBadReturnType: <function> = fn_decl @RuntimeCallBadReturnType [template] {
// CHECK:STDOUT: %a.loc43_29.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: f64 = bind_name a, %a.loc43_29.1
// CHECK:STDOUT: %b.loc43_37.1: f64 = param b
// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: f64 = bind_name b, %b.loc43_37.1
// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TooFew() -> f64;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TooMany(%a: f64, %b: f64) -> f64;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @BadReturnType(%a: f64) -> bool;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @JustRight(%a: f64) -> f64 = "float.negate";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %TooFew.ref: <function> = name_ref TooFew, file.%TooFew [template = file.%TooFew]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %TooFew.call: init f64 = call %TooFew.ref(<invalid>) [template = <error>]
// CHECK:STDOUT: %.loc29_19.1: f64 = value_of_initializer %TooFew.call [template = <error>]
// CHECK:STDOUT: %.loc29_19.2: f64 = converted %TooFew.call, %.loc29_19.1 [template = <error>]
// CHECK:STDOUT: return %.loc29_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: f64, %b: f64, %c: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %TooMany.ref: <function> = name_ref TooMany, file.%TooMany [template = file.%TooMany]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %c.ref: f64 = name_ref c, %c
// CHECK:STDOUT: %TooMany.call: init f64 = call %TooMany.ref(<invalid>) [template = <error>]
// CHECK:STDOUT: %.loc40_26.1: f64 = value_of_initializer %TooMany.call [template = <error>]
// CHECK:STDOUT: %.loc40_26.2: f64 = converted %TooMany.call, %.loc40_26.1 [template = <error>]
// CHECK:STDOUT: return %.loc40_26.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: f64, %b: f64) -> bool {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %BadReturnType.ref: <function> = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %BadReturnType.call: init bool = call %BadReturnType.ref(<invalid>) [template = <error>]
// CHECK:STDOUT: %.loc50_29.1: bool = value_of_initializer %BadReturnType.call [template = <error>]
// CHECK:STDOUT: %.loc50_29.2: bool = converted %BadReturnType.call, %.loc50_29.1 [template = <error>]
// CHECK:STDOUT: return %.loc50_29.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
+211
View File
@@ -0,0 +1,211 @@
// 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
// --- float_sub.carbon
fn Sub(a: f64, b: f64) -> f64 = "float.sub";
fn RuntimeCall(a: f64, b: f64) -> f64 {
return Sub(a, b);
}
var x: f64 = Sub(2.0, 0.5);
// --- fail_bad_decl.carbon
package FailBadDecl api;
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.sub".
// CHECK:STDERR: fn TooFew(a: f64) -> f64 = "float.sub";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn TooFew(a: f64) -> f64 = "float.sub";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.sub".
// CHECK:STDERR: fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.sub";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.sub";
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+3]]:1: ERROR: Invalid signature for builtin function "float.sub".
// CHECK:STDERR: fn BadReturnType(a: f64, b: f64) -> bool = "float.sub";
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fn BadReturnType(a: f64, b: f64) -> bool = "float.sub";
fn JustRight(a: f64, b: f64) -> f64 = "float.sub";
fn RuntimeCallTooFew(a: f64) -> f64 {
return TooFew(a);
}
fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 {
return TooMany(a, b, c);
}
fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool {
return BadReturnType(a, b);
}
// CHECK:STDOUT: --- float_sub.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: f64 = float_literal 2 [template]
// CHECK:STDOUT: %.2: f64 = float_literal 0.5 [template]
// CHECK:STDOUT: %.3: f64 = float_literal 1.5 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Sub = %Sub
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
// CHECK:STDOUT: .x = %x
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Sub: <function> = fn_decl @Sub [template] {
// CHECK:STDOUT: %a.loc2_8.1: f64 = param a
// CHECK:STDOUT: @Sub.%a: f64 = bind_name a, %a.loc2_8.1
// CHECK:STDOUT: %b.loc2_16.1: f64 = param b
// CHECK:STDOUT: @Sub.%b: f64 = bind_name b, %b.loc2_16.1
// CHECK:STDOUT: @Sub.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCall: <function> = fn_decl @RuntimeCall [template] {
// CHECK:STDOUT: %a.loc4_16.1: f64 = param a
// CHECK:STDOUT: @RuntimeCall.%a: f64 = bind_name a, %a.loc4_16.1
// CHECK:STDOUT: %b.loc4_24.1: f64 = param b
// CHECK:STDOUT: @RuntimeCall.%b: f64 = bind_name b, %b.loc4_24.1
// CHECK:STDOUT: @RuntimeCall.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %x.var: ref f64 = var x
// CHECK:STDOUT: %x: ref f64 = bind_name x, %x.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Sub(%a: f64, %b: f64) -> f64 = "float.sub";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCall(%a: f64, %b: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Sub.ref: <function> = name_ref Sub, file.%Sub [template = file.%Sub]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %float.sub: init f64 = call %Sub.ref(%a.ref, %b.ref)
// CHECK:STDOUT: %.loc5_19.1: f64 = value_of_initializer %float.sub
// CHECK:STDOUT: %.loc5_19.2: f64 = converted %float.sub, %.loc5_19.1
// CHECK:STDOUT: return %.loc5_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Sub.ref: <function> = name_ref Sub, file.%Sub [template = file.%Sub]
// CHECK:STDOUT: %.loc8_18: f64 = float_literal 2 [template = constants.%.1]
// CHECK:STDOUT: %.loc8_23: f64 = float_literal 0.5 [template = constants.%.2]
// CHECK:STDOUT: %float.sub: init f64 = call %Sub.ref(%.loc8_18, %.loc8_23) [template = constants.%.3]
// CHECK:STDOUT: assign file.%x.var, %float.sub
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_bad_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .TooFew = %TooFew
// CHECK:STDOUT: .TooMany = %TooMany
// CHECK:STDOUT: .BadReturnType = %BadReturnType
// CHECK:STDOUT: .JustRight = %JustRight
// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew
// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany
// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %TooFew: <function> = fn_decl @TooFew [template] {
// CHECK:STDOUT: %a.loc8_11.1: f64 = param a
// CHECK:STDOUT: @TooFew.%a: f64 = bind_name a, %a.loc8_11.1
// CHECK:STDOUT: @TooFew.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %TooMany: <function> = fn_decl @TooMany [template] {
// CHECK:STDOUT: %a.loc13_12.1: f64 = param a
// CHECK:STDOUT: @TooMany.%a: f64 = bind_name a, %a.loc13_12.1
// CHECK:STDOUT: %b.loc13_20.1: f64 = param b
// CHECK:STDOUT: @TooMany.%b: f64 = bind_name b, %b.loc13_20.1
// CHECK:STDOUT: %c.loc13_28.1: f64 = param c
// CHECK:STDOUT: @TooMany.%c: f64 = bind_name c, %c.loc13_28.1
// CHECK:STDOUT: @TooMany.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %BadReturnType: <function> = fn_decl @BadReturnType [template] {
// CHECK:STDOUT: %a.loc17_18.1: f64 = param a
// CHECK:STDOUT: @BadReturnType.%a: f64 = bind_name a, %a.loc17_18.1
// CHECK:STDOUT: %b.loc17_26.1: f64 = param b
// CHECK:STDOUT: @BadReturnType.%b: f64 = bind_name b, %b.loc17_26.1
// CHECK:STDOUT: @BadReturnType.%return: ref bool = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %JustRight: <function> = fn_decl @JustRight [template] {
// CHECK:STDOUT: %a.loc18_14.1: f64 = param a
// CHECK:STDOUT: @JustRight.%a: f64 = bind_name a, %a.loc18_14.1
// CHECK:STDOUT: %b.loc18_22.1: f64 = param b
// CHECK:STDOUT: @JustRight.%b: f64 = bind_name b, %b.loc18_22.1
// CHECK:STDOUT: @JustRight.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallTooFew: <function> = fn_decl @RuntimeCallTooFew [template] {
// CHECK:STDOUT: %a.loc20_22.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallTooFew.%a: f64 = bind_name a, %a.loc20_22.1
// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallTooMany: <function> = fn_decl @RuntimeCallTooMany [template] {
// CHECK:STDOUT: %a.loc24_23.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallTooMany.%a: f64 = bind_name a, %a.loc24_23.1
// CHECK:STDOUT: %b.loc24_31.1: f64 = param b
// CHECK:STDOUT: @RuntimeCallTooMany.%b: f64 = bind_name b, %b.loc24_31.1
// CHECK:STDOUT: %c.loc24_39.1: f64 = param c
// CHECK:STDOUT: @RuntimeCallTooMany.%c: f64 = bind_name c, %c.loc24_39.1
// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref f64 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %RuntimeCallBadReturnType: <function> = fn_decl @RuntimeCallBadReturnType [template] {
// CHECK:STDOUT: %a.loc28_29.1: f64 = param a
// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: f64 = bind_name a, %a.loc28_29.1
// CHECK:STDOUT: %b.loc28_37.1: f64 = param b
// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: f64 = bind_name b, %b.loc28_37.1
// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TooFew(%a: f64) -> f64;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TooMany(%a: f64, %b: f64, %c: f64) -> f64;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @BadReturnType(%a: f64, %b: f64) -> bool;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @JustRight(%a: f64, %b: f64) -> f64 = "float.sub";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %TooFew.ref: <function> = name_ref TooFew, file.%TooFew [template = file.%TooFew]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %TooFew.call: init f64 = call %TooFew.ref(%a.ref)
// CHECK:STDOUT: %.loc21_19.1: f64 = value_of_initializer %TooFew.call
// CHECK:STDOUT: %.loc21_19.2: f64 = converted %TooFew.call, %.loc21_19.1
// CHECK:STDOUT: return %.loc21_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: f64, %b: f64, %c: f64) -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %TooMany.ref: <function> = name_ref TooMany, file.%TooMany [template = file.%TooMany]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %c.ref: f64 = name_ref c, %c
// CHECK:STDOUT: %TooMany.call: init f64 = call %TooMany.ref(%a.ref, %b.ref, %c.ref)
// CHECK:STDOUT: %.loc25_26.1: f64 = value_of_initializer %TooMany.call
// CHECK:STDOUT: %.loc25_26.2: f64 = converted %TooMany.call, %.loc25_26.1
// CHECK:STDOUT: return %.loc25_26.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: f64, %b: f64) -> bool {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %BadReturnType.ref: <function> = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType]
// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a
// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b
// CHECK:STDOUT: %BadReturnType.call: init bool = call %BadReturnType.ref(%a.ref, %b.ref)
// CHECK:STDOUT: %.loc29_29.1: bool = value_of_initializer %BadReturnType.call
// CHECK:STDOUT: %.loc29_29.2: bool = converted %BadReturnType.call, %.loc29_29.1
// CHECK:STDOUT: return %.loc29_29.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -19,7 +19,7 @@ fn F() {
// CHECK:STDOUT: --- fail_param_type.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: f64 = real_literal 10e-1 [template]
// CHECK:STDOUT: %.1: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.2: type = tuple_type () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -45,7 +45,7 @@ fn F() {
// CHECK:STDOUT: fn @F() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %G.ref: <function> = name_ref G, file.%G [template = file.%G]
// CHECK:STDOUT: %.loc16: f64 = real_literal 10e-1 [template = constants.%.1]
// CHECK:STDOUT: %.loc16: f64 = float_literal 1 [template = constants.%.1]
// CHECK:STDOUT: %G.call: init () = call %G.ref(<invalid>) [template = <error>]
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -16,7 +16,7 @@ fn Run() {
// CHECK:STDOUT: --- fail_return_type_mismatch.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: f64 = real_literal 10e-1 [template]
// CHECK:STDOUT: %.1: f64 = float_literal 1 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -34,7 +34,7 @@ fn Run() {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Foo() -> f64 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc7: f64 = real_literal 10e-1 [template = constants.%.1]
// CHECK:STDOUT: %.loc7: f64 = float_literal 1 [template = constants.%.1]
// CHECK:STDOUT: return %.loc7
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -20,7 +20,7 @@ var b: i32 = a[2.6];
// CHECK:STDOUT: %.5: type = tuple_type (i32) [template]
// CHECK:STDOUT: %.6: i32 = int_literal 0 [template]
// CHECK:STDOUT: %.7: [i32; 1] = tuple_value (%.4) [template]
// CHECK:STDOUT: %.8: f64 = real_literal 26e-1 [template]
// CHECK:STDOUT: %.8: f64 = float_literal 2.6000000000000001 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -49,7 +49,7 @@ var b: i32 = a[2.6];
// CHECK:STDOUT: %.loc7_24: init [i32; 1] = converted %.loc7_23.1, %.loc7_23.5 [template = constants.%.7]
// CHECK:STDOUT: assign file.%a.var, %.loc7_24
// CHECK:STDOUT: %a.ref: ref [i32; 1] = name_ref a, file.%a
// CHECK:STDOUT: %.loc11_16: f64 = real_literal 26e-1 [template = constants.%.8]
// CHECK:STDOUT: %.loc11_16: f64 = float_literal 2.6000000000000001 [template = constants.%.8]
// CHECK:STDOUT: %.loc11_19.1: ref i32 = array_index %a.ref, <error>
// CHECK:STDOUT: %.loc11_19.2: i32 = bind_value %.loc11_19.1
// CHECK:STDOUT: assign file.%b.var, %.loc11_19.2
@@ -19,7 +19,7 @@ var b: i32 = a[2.6];
// CHECK:STDOUT: %.4: i32 = int_literal 12 [template]
// CHECK:STDOUT: %.5: i32 = int_literal 6 [template]
// CHECK:STDOUT: %.6: (i32, i32) = tuple_value (%.4, %.5) [template]
// CHECK:STDOUT: %.7: f64 = real_literal 26e-1 [template]
// CHECK:STDOUT: %.7: f64 = float_literal 2.6000000000000001 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -50,7 +50,7 @@ var b: i32 = a[2.6];
// CHECK:STDOUT: %.loc7_28: init (i32, i32) = converted %.loc7_27.1, %.loc7_27.6 [template = constants.%.6]
// CHECK:STDOUT: assign file.%a.var, %.loc7_28
// CHECK:STDOUT: %a.ref: ref (i32, i32) = name_ref a, file.%a
// CHECK:STDOUT: %.loc11_16: f64 = real_literal 26e-1 [template = constants.%.7]
// CHECK:STDOUT: %.loc11_16: f64 = float_literal 2.6000000000000001 [template = constants.%.7]
// CHECK:STDOUT: %.loc11_19: ref <error> = tuple_index %a.ref, <error>
// CHECK:STDOUT: assign file.%b.var, <error>
// CHECK:STDOUT: return
@@ -16,7 +16,7 @@ fn Main() {
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: i32 = int_literal 3 [template]
// CHECK:STDOUT: %.2: f64 = real_literal 56e-1 [template]
// CHECK:STDOUT: %.2: f64 = float_literal 5.6000000000000005 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -35,7 +35,7 @@ fn Main() {
// CHECK:STDOUT: %.loc8: i32 = int_literal 3 [template = constants.%.1]
// CHECK:STDOUT: assign %a.var, %.loc8
// CHECK:STDOUT: %a.ref: ref i32 = name_ref a, %a
// CHECK:STDOUT: %.loc12: f64 = real_literal 56e-1 [template = constants.%.2]
// CHECK:STDOUT: %.loc12: f64 = float_literal 5.6000000000000005 [template = constants.%.2]
// CHECK:STDOUT: assign %a.ref, <error>
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -29,7 +29,7 @@ fn Main() -> i32 {
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: i32 = int_literal 12 [template]
// CHECK:STDOUT: %.2: f64 = real_literal 34e-1 [template]
// CHECK:STDOUT: %.2: f64 = float_literal 3.4000000000000004 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -46,7 +46,7 @@ fn Main() -> i32 {
// CHECK:STDOUT: fn @Main() -> i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc25_10: i32 = int_literal 12 [template = constants.%.1]
// CHECK:STDOUT: %.loc25_15: f64 = real_literal 34e-1 [template = constants.%.2]
// CHECK:STDOUT: %.loc25_15: f64 = float_literal 3.4000000000000004 [template = constants.%.2]
// CHECK:STDOUT: %.loc25_21: i32 = int_literal 12 [template = constants.%.1]
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
@@ -103,7 +103,7 @@ fn AddressOfParam(param: i32) {
// CHECK:STDOUT: %.3: type = ptr_type i32 [template]
// CHECK:STDOUT: %.4: bool = bool_literal true [template]
// CHECK:STDOUT: %.5: type = ptr_type bool [template]
// CHECK:STDOUT: %.6: f64 = real_literal 10e-1 [template]
// CHECK:STDOUT: %.6: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.7: type = ptr_type f64 [template]
// CHECK:STDOUT: %.8: type = ptr_type String [template]
// CHECK:STDOUT: %.9: String = string_literal "Hello" [template]
@@ -161,7 +161,7 @@ fn AddressOfParam(param: i32) {
// CHECK:STDOUT: %.loc16_3: i32* = addr_of <error> [template = <error>]
// CHECK:STDOUT: %.loc21_4: bool = bool_literal true [template = constants.%.4]
// CHECK:STDOUT: %.loc21_3: bool* = addr_of <error> [template = <error>]
// CHECK:STDOUT: %.loc26_4: f64 = real_literal 10e-1 [template = constants.%.6]
// CHECK:STDOUT: %.loc26_4: f64 = float_literal 1 [template = constants.%.6]
// CHECK:STDOUT: %.loc26_3: f64* = addr_of <error> [template = <error>]
// CHECK:STDOUT: %.loc31_4: String = string_literal "Hello" [template = constants.%.9]
// CHECK:STDOUT: %.loc31_3: String* = addr_of <error> [template = <error>]
@@ -18,7 +18,7 @@ fn Mismatch() -> i32 {
// CHECK:STDOUT: --- fail_returned_var_type.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: f64 = real_literal 0e-1 [template]
// CHECK:STDOUT: %.1: f64 = float_literal 0 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -35,7 +35,7 @@ fn Mismatch() -> i32 {
// CHECK:STDOUT: fn @Mismatch() -> i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %v: f64 = bind_name v, <error>
// CHECK:STDOUT: %.loc14: f64 = real_literal 0e-1 [template = constants.%.1]
// CHECK:STDOUT: %.loc14: f64 = float_literal 0 [template = constants.%.1]
// CHECK:STDOUT: assign <error>, <error>
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
+2 -2
View File
@@ -14,7 +14,7 @@ fn Main() -> i32 {
// CHECK:STDOUT: --- fail_type_mismatch.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: f64 = real_literal 10e-1 [template]
// CHECK:STDOUT: %.1: f64 = float_literal 1 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -30,7 +30,7 @@ fn Main() -> i32 {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Main() -> i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc11: f64 = real_literal 10e-1 [template = constants.%.1]
// CHECK:STDOUT: %.loc11: f64 = float_literal 1 [template = constants.%.1]
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -13,7 +13,7 @@ var x: {.a: i32} = {.b = 1.0};
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: type = struct_type {.a: i32} [template]
// CHECK:STDOUT: %.2: f64 = real_literal 10e-1 [template]
// CHECK:STDOUT: %.2: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.3: type = struct_type {.b: f64} [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -30,7 +30,7 @@ var x: {.a: i32} = {.b = 1.0};
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc10_26: f64 = real_literal 10e-1 [template = constants.%.2]
// CHECK:STDOUT: %.loc10_26: f64 = float_literal 1 [template = constants.%.2]
// CHECK:STDOUT: %.loc10_29: {.b: f64} = struct_literal (%.loc10_26)
// CHECK:STDOUT: assign file.%x.var, <error>
// CHECK:STDOUT: return
@@ -14,7 +14,7 @@ var y: i32 = x.b;
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: type = struct_type {.a: f64} [template]
// CHECK:STDOUT: %.2: f64 = real_literal 40e-1 [template]
// CHECK:STDOUT: %.2: f64 = float_literal 4 [template]
// CHECK:STDOUT: %.3: {.a: f64} = struct_value (%.2) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -34,7 +34,7 @@ var y: i32 = x.b;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc7_26: f64 = real_literal 40e-1 [template = constants.%.2]
// CHECK:STDOUT: %.loc7_26: f64 = float_literal 4 [template = constants.%.2]
// CHECK:STDOUT: %.loc7_29.1: {.a: f64} = struct_literal (%.loc7_26)
// CHECK:STDOUT: %.loc7_29.2: init {.a: f64} = struct_init (%.loc7_26) to file.%x.var [template = constants.%.3]
// CHECK:STDOUT: %.loc7_30: init {.a: f64} = converted %.loc7_29.1, %.loc7_29.2 [template = constants.%.3]
+2 -2
View File
@@ -13,7 +13,7 @@ var z: i32 = y;
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: type = struct_type {.a: f64, .b: i32} [template]
// CHECK:STDOUT: %.2: type = ptr_type {.a: f64, .b: i32} [template]
// CHECK:STDOUT: %.3: f64 = real_literal 0e-1 [template]
// CHECK:STDOUT: %.3: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.4: i32 = int_literal 1 [template]
// CHECK:STDOUT: %.5: {.a: f64, .b: i32} = struct_value (%.3, %.4) [template]
// CHECK:STDOUT: }
@@ -37,7 +37,7 @@ var z: i32 = y;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc7_35: f64 = real_literal 0e-1 [template = constants.%.3]
// CHECK:STDOUT: %.loc7_35: f64 = float_literal 0 [template = constants.%.3]
// CHECK:STDOUT: %.loc7_45: i32 = int_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc7_46.1: {.a: f64, .b: i32} = struct_literal (%.loc7_35, %.loc7_45)
// CHECK:STDOUT: %.loc7_46.2: ref f64 = struct_access file.%x.var, element0
@@ -16,7 +16,7 @@ var x: (i32, i32) = (2, 65.89);
// CHECK:STDOUT: %.2: type = tuple_type (i32, i32) [template]
// CHECK:STDOUT: %.3: type = ptr_type (i32, i32) [template]
// CHECK:STDOUT: %.4: i32 = int_literal 2 [template]
// CHECK:STDOUT: %.5: f64 = real_literal 6589e-2 [template]
// CHECK:STDOUT: %.5: f64 = float_literal 65.890000000000001 [template]
// CHECK:STDOUT: %.6: type = tuple_type (i32, f64) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -35,7 +35,7 @@ var x: (i32, i32) = (2, 65.89);
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc10_22: i32 = int_literal 2 [template = constants.%.4]
// CHECK:STDOUT: %.loc10_25: f64 = real_literal 6589e-2 [template = constants.%.5]
// CHECK:STDOUT: %.loc10_25: f64 = float_literal 65.890000000000001 [template = constants.%.5]
// CHECK:STDOUT: %.loc10_30.1: (i32, f64) = tuple_literal (%.loc10_22, %.loc10_25)
// CHECK:STDOUT: %.loc10_30.2: ref i32 = tuple_access file.%x.var, element0
// CHECK:STDOUT: %.loc10_30.3: init i32 = initialize_from %.loc10_22 to %.loc10_30.2 [template = constants.%.4]
@@ -14,7 +14,7 @@ fn Main() {
// CHECK:STDOUT: --- fail_init_type_mismatch.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: f64 = real_literal 10e-1 [template]
// CHECK:STDOUT: %.1: f64 = float_literal 1 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -30,7 +30,7 @@ fn Main() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %x.var: ref i32 = var x
// CHECK:STDOUT: %x: ref i32 = bind_name x, %x.var
// CHECK:STDOUT: %.loc11: f64 = real_literal 10e-1 [template = constants.%.1]
// CHECK:STDOUT: %.loc11: f64 = float_literal 1 [template = constants.%.1]
// CHECK:STDOUT: assign %x.var, <error>
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -258,6 +258,8 @@ CARBON_DIAGNOSTIC_KIND(DerefOfNonPointer)
CARBON_DIAGNOSTIC_KIND(DerefOfType)
CARBON_DIAGNOSTIC_KIND(CompileTimeBindingInVarDecl)
CARBON_DIAGNOSTIC_KIND(CompoundMemberAccessDoesNotUseBase)
CARBON_DIAGNOSTIC_KIND(RealMantissaTooLargeForI64)
CARBON_DIAGNOSTIC_KIND(RealExponentTooLargeForI64)
CARBON_DIAGNOSTIC_KIND(NameAmbiguousDueToExtend)
CARBON_DIAGNOSTIC_KIND(NameNotFound)
CARBON_DIAGNOSTIC_KIND(NameDeclDuplicate)
+36
View File
@@ -371,6 +371,35 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id,
context.GetValue(arg_ids[0]), context.GetValue(arg_ids[1])));
return;
}
case SemIR::BuiltinFunctionKind::FloatNegate: {
context.SetLocal(inst_id, context.builder().CreateFNeg(
context.GetValue(arg_ids[0]), "fneg"));
return;
}
case SemIR::BuiltinFunctionKind::FloatAdd: {
context.SetLocal(inst_id, context.builder().CreateFAdd(
context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1]), "fadd"));
return;
}
case SemIR::BuiltinFunctionKind::FloatSub: {
context.SetLocal(inst_id, context.builder().CreateFSub(
context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1]), "fsub"));
return;
}
case SemIR::BuiltinFunctionKind::FloatMul: {
context.SetLocal(inst_id, context.builder().CreateFMul(
context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1]), "fmul"));
return;
}
case SemIR::BuiltinFunctionKind::FloatDiv: {
context.SetLocal(inst_id, context.builder().CreateFDiv(
context.GetValue(arg_ids[0]),
context.GetValue(arg_ids[1]), "fdiv"));
return;
}
}
CARBON_FATAL() << "Unsupported builtin call.";
@@ -421,6 +450,13 @@ auto HandleDeref(FunctionContext& context, SemIR::InstId inst_id,
context.SetLocal(inst_id, context.GetValue(inst.pointer_id));
}
auto HandleFloatLiteral(FunctionContext& context, SemIR::InstId inst_id,
SemIR::FloatLiteral inst) -> void {
const llvm::APFloat& value = context.sem_ir().floats().Get(inst.float_id);
context.SetLocal(
inst_id, llvm::ConstantFP::get(context.builder().getDoubleTy(), value));
}
auto HandleFunctionDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
SemIR::FunctionDecl inst) -> void {
FatalErrorIfEncountered(inst);
+5
View File
@@ -32,6 +32,11 @@ auto HandleFacetTypeAccess(FunctionContext& context, SemIR::InstId inst_id,
context.SetLocal(inst_id, context.GetTypeAsValue());
}
auto HandleFloatType(FunctionContext& context, SemIR::InstId inst_id,
SemIR::FloatType /*inst*/) -> void {
context.SetLocal(inst_id, context.GetTypeAsValue());
}
auto HandleInterfaceType(FunctionContext& context, SemIR::InstId inst_id,
SemIR::InterfaceType /*inst*/) -> void {
context.SetLocal(inst_id, context.GetTypeAsValue());
+53
View File
@@ -0,0 +1,53 @@
// 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
fn Negate(a: f64) -> f64 = "float.negate";
fn TestNegate(a: f64) -> f64 { return Negate(a); }
fn Add(a: f64, b: f64) -> f64 = "float.add";
fn TestAdd(a: f64, b: f64) -> f64 { return Add(a, b); }
fn Sub(a: f64, b: f64) -> f64 = "float.sub";
fn TestSub(a: f64, b: f64) -> f64 { return Sub(a, b); }
fn Mul(a: f64, b: f64) -> f64 = "float.mul";
fn TestMul(a: f64, b: f64) -> f64 { return Mul(a, b); }
fn Div(a: f64, b: f64) -> f64 = "float.div";
fn TestDiv(a: f64, b: f64) -> f64 { return Div(a, b); }
// CHECK:STDOUT: ; ModuleID = 'float.carbon'
// CHECK:STDOUT: source_filename = "float.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: define double @TestNegate(double %a) {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %float.negate.fneg = fneg double %a
// CHECK:STDOUT: ret double %float.negate.fneg
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define double @TestAdd(double %a, double %b) {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %float.add.fadd = fadd double %a, %b
// CHECK:STDOUT: ret double %float.add.fadd
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define double @TestSub(double %a, double %b) {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %float.sub.fsub = fsub double %a, %b
// CHECK:STDOUT: ret double %float.sub.fsub
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define double @TestMul(double %a, double %b) {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %float.mul.fmul = fmul double %a, %b
// CHECK:STDOUT: ret double %float.mul.fmul
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define double @TestDiv(double %a, double %b) {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %float.div.fdiv = fdiv double %a, %b
// CHECK:STDOUT: ret double %float.div.fdiv
// CHECK:STDOUT: }
@@ -75,6 +75,17 @@ struct AnyInt {
}
};
// Constraint that requires the type to be a float type.
struct AnyFloat {
static auto Check(const File& sem_ir, ValidateState& state, TypeId type_id)
-> bool {
if (BuiltinType<InstId::BuiltinFloatType>::Check(sem_ir, state, type_id)) {
return true;
}
return sem_ir.types().Is<FloatType>(type_id);
}
};
// Constraint that requires the type to be the type type.
using Type = BuiltinType<InstId::BuiltinTypeType>;
@@ -139,6 +150,10 @@ using IntT = TypeParam<0, AnyInt>;
// generic type parameter that is constrained to be an integer type.
using IntU = TypeParam<1, AnyInt>;
// 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>;
// Not a builtin function.
constexpr BuiltinInfo None = {"", nullptr};
@@ -260,6 +275,26 @@ constexpr BuiltinInfo IntGreater = {"int.greater",
constexpr BuiltinInfo IntGreaterEq = {
"int.greater_eq", ValidateSignature<auto(IntT, IntT)->Bool>};
// "float.negate": float negation.
constexpr BuiltinInfo FloatNegate = {"float.negate",
ValidateSignature<auto(FloatT)->FloatT>};
// "float.add": float addition.
constexpr BuiltinInfo FloatAdd = {
"float.add", ValidateSignature<auto(FloatT, FloatT)->FloatT>};
// "float.sub": float subtraction.
constexpr BuiltinInfo FloatSub = {
"float.sub", ValidateSignature<auto(FloatT, FloatT)->FloatT>};
// "float.mul": float multiplication.
constexpr BuiltinInfo FloatMul = {
"float.mul", ValidateSignature<auto(FloatT, FloatT)->FloatT>};
// "float.div": float division.
constexpr BuiltinInfo FloatDiv = {
"float.div", ValidateSignature<auto(FloatT, FloatT)->FloatT>};
} // namespace BuiltinFunctionInfo
CARBON_DEFINE_ENUM_CLASS_NAMES(BuiltinFunctionKind) = {
@@ -55,4 +55,11 @@ CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntLessEq)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntGreater)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntGreaterEq)
// Float arithmetic.
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatNegate)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatAdd)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatSub)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatMul)
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatDiv)
#undef CARBON_SEM_IR_BUILTIN_FUNCTION_KIND
+20
View File
@@ -207,6 +207,7 @@ static auto GetTypePrecedence(InstKind kind) -> int {
case Builtin::Kind:
case ClassType::Kind:
case FacetTypeAccess::Kind:
case FloatType::Kind:
case ImportRefLoaded::Kind:
case ImportRefUsed::Kind:
case InterfaceType::Kind:
@@ -246,6 +247,7 @@ static auto GetTypePrecedence(InstKind kind) -> int {
case Converted::Kind:
case Deref::Kind:
case FieldDecl::Kind:
case FloatLiteral::Kind:
case FunctionDecl::Kind:
case ImplDecl::Kind:
case ImportRefUnloaded::Kind:
@@ -382,6 +384,21 @@ static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir,
push_inst_id(inst.facet_id);
break;
}
case CARBON_KIND(FloatType inst): {
// TODO: Is this okay?
if (step.index == 1) {
out << ")";
} else if (auto width_value =
sem_ir.insts().TryGetAs<IntLiteral>(inst.bit_width_id)) {
out << "f";
sem_ir.ints().Get(width_value->int_id).print(out, /*isSigned=*/false);
} else {
out << "Core.Float(";
steps.push_back(step.Next());
push_inst_id(inst.bit_width_id);
}
break;
}
case ImportRefLoaded::Kind:
case ImportRefUsed::Kind: {
auto import_ir_inst = sem_ir.import_ir_insts().Get(
@@ -505,6 +522,7 @@ static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir,
case Converted::Kind:
case Deref::Kind:
case FieldDecl::Kind:
case FloatLiteral::Kind:
case FunctionDecl::Kind:
case ImplDecl::Kind:
case ImportRefUnloaded::Kind:
@@ -623,6 +641,8 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
case ClassType::Kind:
case ConstType::Kind:
case FacetTypeAccess::Kind:
case FloatLiteral::Kind:
case FloatType::Kind:
case InterfaceDecl::Kind:
case InterfaceType::Kind:
case InterfaceWitness::Kind:
+4
View File
@@ -115,6 +115,10 @@ class File : public Printable<File> {
auto reals() const -> const ValueStore<RealId>& {
return value_stores_->reals();
}
auto floats() -> ValueStore<FloatId>& { return value_stores_->floats(); }
auto floats() const -> const ValueStore<FloatId>& {
return value_stores_->floats();
}
auto string_literal_values() -> StringStoreWrapper<StringLiteralValueId>& {
return value_stores_->string_literal_values();
}
+8
View File
@@ -614,6 +614,12 @@ class Formatter {
.print(out_, sem_ir_.types().IsSignedInt(inst.type_id));
}
auto FormatInstructionRHS(FloatLiteral inst) -> void {
llvm::SmallVector<char, 16> buffer;
sem_ir_.floats().Get(inst.float_id).toString(buffer);
out_ << " " << buffer;
}
auto FormatInstructionRHS(ImportRefUnloaded inst) -> void {
FormatArgs(inst.import_ir_inst_id);
out_ << ", unloaded";
@@ -675,6 +681,8 @@ class Formatter {
auto FormatArg(IntKind k) -> void { k.Print(out_); }
auto FormatArg(FloatKind k) -> void { k.Print(out_); }
auto FormatArg(ImplId id) -> void { FormatImplName(id); }
auto FormatArg(ImportIRId id) -> void { out_ << id; }
+2 -2
View File
@@ -118,11 +118,11 @@ using IdKind = TypeEnum<
// From sem_ir/builtin_kind.h.
BuiltinKind,
// From base/value_store.h.
IntId, RealId, StringLiteralValueId,
IntId, RealId, FloatId, StringLiteralValueId,
// From sem_ir/id.h.
InstId, ConstantId, BindNameId, FunctionId, ClassId, InterfaceId, ImplId,
ImportIRId, ImportIRInstId, LocId, BoolValue, IntKind, NameId, NameScopeId,
InstBlockId, TypeId, TypeBlockId, ElementIndex>;
InstBlockId, TypeId, TypeBlockId, ElementIndex, FloatKind>;
} // namespace Carbon::SemIR
+7
View File
@@ -332,6 +332,13 @@ struct IntKind : public IdBase, public Printable<IntKind> {
constexpr IntKind IntKind::Unsigned = IntKind(0);
constexpr IntKind IntKind::Signed = IntKind(1);
// A float kind value
struct FloatKind : public IdBase, public Printable<FloatKind> {
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void { out << "float"; }
};
// The ID of a name. A name is either a string or a special name such as
// `self`, `Self`, or `base`.
struct NameId : public IdBase, public Printable<NameId> {
+2
View File
@@ -49,6 +49,8 @@ CARBON_SEM_IR_INST_KIND(ConstType)
CARBON_SEM_IR_INST_KIND(Converted)
CARBON_SEM_IR_INST_KIND(Deref)
CARBON_SEM_IR_INST_KIND(FacetTypeAccess)
CARBON_SEM_IR_INST_KIND(FloatLiteral)
CARBON_SEM_IR_INST_KIND(FloatType)
CARBON_SEM_IR_INST_KIND(FieldDecl)
CARBON_SEM_IR_INST_KIND(FunctionDecl)
CARBON_SEM_IR_INST_KIND(ImplDecl)
+18
View File
@@ -444,6 +444,24 @@ struct FacetTypeAccess {
InstId facet_id;
};
struct FloatLiteral {
static constexpr auto Kind =
InstKind::FloatLiteral.Define<Parse::RealLiteralId>("float_literal");
TypeId type_id;
FloatId float_id;
};
struct FloatType {
static constexpr auto Kind =
InstKind::FloatType.Define<Parse::NodeId>("float_type");
TypeId type_id;
// TODO: Consider adding a more compact way of representing either a small
// float bit width or an inst_id.
InstId bit_width_id;
};
// A field in a class, of the form `var field: field_type;`. The type of the
// `FieldDecl` instruction is an `UnboundElementType`.
struct FieldDecl {