Replace FoldingSet with DenseMap for instruction canonicalization. (#3979)

Switch from recursing into non-canonical instruction fields to
separately canonicalizing those fields. This means we now form canonical
`InstBlockId`s, `TypeBlockId`s, `IntId`s, `FloatId`s, and `BindNameId`s
at least in the cases when they're referenced by a constant instruction.

This reduces the overall runtime for @chandlerc's 10MLoC example by
27.5% on my machine.
This commit is contained in:
Richard Smith
2024-05-23 00:48:49 +00:00
committed by GitHub
parent 7b4b7abc6e
commit 5c8fa6ad5c
35 changed files with 479 additions and 505 deletions
+10
View File
@@ -279,6 +279,16 @@ class Hasher {
// state along with the contents.
auto HashSizedBytes(llvm::ArrayRef<std::byte> bytes) -> void;
// Incorporate a dynamically sized sequence of bytes represented as an array
// of objects into the hasher's state.
template <typename T>
requires std::has_unique_object_representations_v<T>
auto HashSizedBytes(llvm::ArrayRef<T> data) -> void {
HashSizedBytes(llvm::ArrayRef<std::byte>(
reinterpret_cast<const std::byte*>(data.data()),
data.size() * sizeof(T)));
}
// An out-of-line, throughput-optimized routine for incorporating a
// dynamically sized sequence when the sequence size is guaranteed to be >32.
// The size is always incorporated into the state.
+1
View File
@@ -283,6 +283,7 @@ struct HashableType {
int ignored = 0;
// See common/hashing.h.
friend auto CarbonHashValue(const HashableType& value, uint64_t seed)
-> HashCode {
Hasher hasher(seed);
+1
View File
@@ -38,6 +38,7 @@ cc_library(
":index_base",
":yaml",
"//common:check",
"//common:hashing",
"//common:ostream",
"@llvm-project//llvm:Support",
],
+99 -19
View File
@@ -8,6 +8,7 @@
#include <type_traits>
#include "common/check.h"
#include "common/hashing.h"
#include "common/ostream.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
@@ -21,13 +22,13 @@
namespace Carbon {
// The value of a real literal.
// The value of a real literal token.
//
// This is either a dyadic fraction (mantissa * 2^exponent) or a decadic
// fraction (mantissa * 10^exponent).
//
// TODO: For SemIR, replace this with a Rational type, per the design:
// docs/design/expressions/literals.md
// These values are not canonicalized, because we don't expect them to repeat
// and don't use them in SemIR values.
class Real : public Printable<Real> {
public:
auto Print(llvm::raw_ostream& output_stream) const -> void {
@@ -48,9 +49,12 @@ class Real : public Printable<Real> {
bool is_decimal;
};
// Corresponds to an integer value represented by an APInt.
// Corresponds to an integer value represented by an APInt. This is used both
// for integer literal tokens, which are unsigned and have an unspecified
// bit-width, and integer values in SemIR, which have a signedness and bit-width
// matching their type.
struct IntId : public IdBase, public Printable<IntId> {
using ValueType = const llvm::APInt;
using ValueType = llvm::APInt;
static const IntId Invalid;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
@@ -60,9 +64,10 @@ struct IntId : public IdBase, public Printable<IntId> {
};
constexpr IntId IntId::Invalid(IntId::InvalidIndex);
// Corresponds to a float value represented by an APFloat.
// Corresponds to a float value represented by an APFloat. This is used for
// floating-point values in SemIR.
struct FloatId : public IdBase, public Printable<FloatId> {
using ValueType = const llvm::APFloat;
using ValueType = llvm::APFloat;
static const FloatId Invalid;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
@@ -72,9 +77,29 @@ struct FloatId : public IdBase, public Printable<FloatId> {
};
constexpr FloatId FloatId::Invalid(FloatId::InvalidIndex);
// DenseMapInfo for llvm::APFloat, for use in the canonical float value store.
// LLVM has an implementation of this but it strangely lives in the non-public
// header lib/IR/LLVMContextImpl.h, so we use our own.
// TODO: Remove this once our new hash table is available.
struct APFloatDenseMapInfo {
static auto getEmptyKey() -> llvm::APFloat {
return llvm::APFloat(llvm::APFloat::Bogus(), 1);
}
static auto getTombstoneKey() -> llvm::APFloat {
return llvm::APFloat(llvm::APFloat::Bogus(), 2);
}
static auto getHashValue(const llvm::APFloat& val) -> unsigned {
return hash_value(val);
}
static auto isEqual(const llvm::APFloat& lhs, const llvm::APFloat& rhs)
-> bool {
return lhs.bitwiseIsEqual(rhs);
}
};
// Corresponds to a Real value.
struct RealId : public IdBase, public Printable<RealId> {
using ValueType = const Real;
using ValueType = Real;
static const RealId Invalid;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
@@ -86,7 +111,7 @@ constexpr RealId RealId::Invalid(RealId::InvalidIndex);
// Corresponds to a StringRef.
struct StringId : public IdBase, public Printable<StringId> {
using ValueType = const std::string;
using ValueType = std::string;
static const StringId Invalid;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
@@ -191,10 +216,62 @@ class ValueStore
llvm::SmallVector<std::decay_t<ValueType>, 0> values_;
};
// A wrapper for accumulating immutable values with deduplication, providing IDs
// to later retrieve the value.
//
// IdT::ValueType must represent the type being indexed.
template <typename IdT,
typename DenseMapInfoT = llvm::DenseMapInfo<typename IdT::ValueType>>
class CanonicalValueStore {
public:
using ValueType = typename IdT::ValueType;
// Stores a canonical copy of the value and returns an ID to reference it.
auto Add(ValueType value) -> IdT {
auto [it, added] = map_.insert({value, IdT::Invalid});
if (added) {
it->second = values_.Add(value);
}
return it->second;
}
// Returns the value for an ID.
auto Get(IdT id) const -> const ValueType& { return values_.Get(id); }
// Reserves space.
auto Reserve(size_t size) -> void {
values_.Reserve(size);
map_.reserve(size);
}
// These are to support printable structures, and are not guaranteed.
auto OutputYaml() const -> Yaml::OutputMapping {
return values_.OutputYaml();
}
auto array_ref() const -> llvm::ArrayRef<ValueType> {
return values_.array_ref();
}
auto size() const -> size_t { return values_.size(); }
private:
// We store two copies of each value: one in the ValueStore for fast mapping
// from IdT to value, and another in the DenseMap for the reverse mapping.
//
// We could avoid this by storing the map instead as a DenseSet<IdT>, but
// there's no way to provide a DenseMapInfo that looks the IDs up in the
// vector.
//
// TODO: Switch to a better representation that avoids the duplication.
ValueStore<IdT> values_;
llvm::DenseMap<ValueType, IdT, DenseMapInfoT> map_;
};
// Storage for StringRefs. The caller is responsible for ensuring storage is
// allocated.
template <>
class ValueStore<StringId> : public Yaml::Printable<ValueStore<StringId>> {
class CanonicalValueStore<StringId>
: public Yaml::Printable<CanonicalValueStore<StringId>> {
public:
// Returns an ID to reference the value. May return an existing ID if the
// string was previously added.
@@ -244,7 +321,8 @@ class ValueStore<StringId> : public Yaml::Printable<ValueStore<StringId>> {
template <typename IdT>
class StringStoreWrapper : public Printable<StringStoreWrapper<IdT>> {
public:
explicit StringStoreWrapper(ValueStore<StringId>* values) : values_(values) {}
explicit StringStoreWrapper(CanonicalValueStore<StringId>* values)
: values_(values) {}
auto Add(llvm::StringRef value) -> IdT {
return IdT(values_->Add(value).index);
@@ -263,9 +341,11 @@ class StringStoreWrapper : public Printable<StringStoreWrapper<IdT>> {
auto size() const -> size_t { return values_->size(); }
private:
ValueStore<StringId>* values_;
CanonicalValueStore<StringId>* values_;
};
using FloatValueStore = CanonicalValueStore<FloatId, APFloatDenseMapInfo>;
// Stores that will be used across compiler phases for a given compilation unit.
// This is provided mainly so that they don't need to be passed separately.
class SharedValueStores : public Yaml::Printable<SharedValueStores> {
@@ -283,12 +363,12 @@ class SharedValueStores : public Yaml::Printable<SharedValueStores> {
auto identifiers() const -> const StringStoreWrapper<IdentifierId>& {
return identifiers_;
}
auto ints() -> ValueStore<IntId>& { return ints_; }
auto ints() const -> const ValueStore<IntId>& { return ints_; }
auto ints() -> CanonicalValueStore<IntId>& { return ints_; }
auto ints() const -> const CanonicalValueStore<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 floats() -> FloatValueStore& { return floats_; }
auto floats() const -> const FloatValueStore& { return floats_; }
auto string_literal_values() -> StringStoreWrapper<StringLiteralValueId>& {
return string_literal_values_;
}
@@ -313,11 +393,11 @@ class SharedValueStores : public Yaml::Printable<SharedValueStores> {
}
private:
ValueStore<IntId> ints_;
CanonicalValueStore<IntId> ints_;
ValueStore<RealId> reals_;
ValueStore<FloatId> floats_;
FloatValueStore floats_;
ValueStore<StringId> strings_;
CanonicalValueStore<StringId> strings_;
StringStoreWrapper<IdentifierId> identifiers_;
StringStoreWrapper<StringLiteralValueId> string_literal_values_;
};
+2 -4
View File
@@ -1076,10 +1076,8 @@ auto Context::GetStructType(SemIR::InstBlockId refs_id) -> SemIR::TypeId {
auto Context::GetTupleType(llvm::ArrayRef<SemIR::TypeId> type_ids)
-> SemIR::TypeId {
// TODO: Deduplicate the type block here. Currently requesting the same tuple
// type more than once will create multiple type blocks, all but one of which
// is unused.
return GetTypeImpl<SemIR::TupleType>(*this, type_blocks().Add(type_ids));
return GetTypeImpl<SemIR::TupleType>(*this,
type_blocks().AddCanonical(type_ids));
}
auto Context::GetAssociatedEntityType(SemIR::InterfaceId interface_id,
+3 -5
View File
@@ -341,15 +341,13 @@ class Context {
auto identifiers() -> StringStoreWrapper<IdentifierId>& {
return sem_ir().identifiers();
}
auto ints() -> ValueStore<IntId>& { return sem_ir().ints(); }
auto ints() -> CanonicalValueStore<IntId>& { return sem_ir().ints(); }
auto reals() -> ValueStore<RealId>& { return sem_ir().reals(); }
auto floats() -> ValueStore<FloatId>& { return sem_ir().floats(); }
auto floats() -> FloatValueStore& { return sem_ir().floats(); }
auto string_literal_values() -> StringStoreWrapper<StringLiteralValueId>& {
return sem_ir().string_literal_values();
}
auto bind_names() -> ValueStore<SemIR::BindNameId>& {
return sem_ir().bind_names();
}
auto bind_names() -> SemIR::BindNameStore& { return sem_ir().bind_names(); }
auto functions() -> ValueStore<SemIR::FunctionId>& {
return sem_ir().functions();
}
+4 -3
View File
@@ -141,9 +141,9 @@ static auto GetConstantValue(Context& context, SemIR::InstBlockId inst_block_id,
const_insts.push_back(const_inst_id);
}
// TODO: If the new block is identical to the original block, return the
// original ID.
return context.inst_blocks().Add(const_insts);
// TODO: If the new block is identical to the original block, and we know the
// old ID was canonical, return the original ID.
return context.inst_blocks().AddCanonical(const_insts);
}
// The constant value of a type block is that type block, but we still need to
@@ -1054,6 +1054,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
case CARBON_KIND(SemIR::BindSymbolicName bind): {
// The constant form of a symbolic binding is an idealized form of the
// original, with no equivalent value.
bind.bind_name_id = context.bind_names().MakeCanonical(bind.bind_name_id);
bind.value_id = SemIR::InstId::Invalid;
return MakeConstantResult(context, bind, Phase::Symbolic);
}
+2 -2
View File
@@ -108,7 +108,7 @@ static auto PopOperand(Context& context, Worklist& worklist, SemIR::IdKind kind,
for (auto i : llvm::reverse(llvm::seq(size))) {
new_inst_block.Set(i, worklist.Pop());
}
return new_inst_block.id().index;
return new_inst_block.GetCanonical().index;
}
case SemIR::IdKind::For<SemIR::TypeBlockId>: {
auto old_type_block_id = static_cast<SemIR::TypeBlockId>(arg);
@@ -119,7 +119,7 @@ static auto PopOperand(Context& context, Worklist& worklist, SemIR::IdKind kind,
new_type_block.Set(size - i - 1,
context.GetTypeIdForTypeInst(worklist.Pop()));
}
return new_type_block.id().index;
return new_type_block.GetCanonical().index;
}
default:
return arg;
@@ -34,7 +34,6 @@ fn B() {}
// CHECK:STDOUT: type2: {constant: template inst+3, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: typeBlock0: {}
// CHECK:STDOUT: typeBlock1: {}
// CHECK:STDOUT: insts:
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+1': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type1}
@@ -96,7 +95,6 @@ fn B() {}
// CHECK:STDOUT: type2: {constant: template inst+3, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: typeBlock0: {}
// CHECK:STDOUT: typeBlock1: {}
// CHECK:STDOUT: insts:
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+1': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type1}
@@ -34,7 +34,6 @@ fn B() {}
// CHECK:STDOUT: type2: {constant: template inst+3, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: typeBlock0: {}
// CHECK:STDOUT: typeBlock1: {}
// CHECK:STDOUT: insts:
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+1': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type1}
@@ -75,7 +74,6 @@ fn B() {}
// CHECK:STDOUT: type2: {constant: template inst+3, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: typeBlock0: {}
// CHECK:STDOUT: typeBlock1: {}
// CHECK:STDOUT: insts:
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+1': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type1}
@@ -31,21 +31,7 @@ fn Foo(n: ()) -> ((), ()) {
// CHECK:STDOUT: type4: {constant: template inst+17, value_rep: {kind: copy, type: type4}}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: typeBlock0: {}
// CHECK:STDOUT: typeBlock1: {}
// CHECK:STDOUT: typeBlock2: {}
// CHECK:STDOUT: typeBlock3: {}
// CHECK:STDOUT: typeBlock4:
// CHECK:STDOUT: 0: type1
// CHECK:STDOUT: 1: type1
// CHECK:STDOUT: typeBlock5: {}
// CHECK:STDOUT: typeBlock6: {}
// CHECK:STDOUT: typeBlock7:
// CHECK:STDOUT: 0: type1
// CHECK:STDOUT: 1: type1
// CHECK:STDOUT: typeBlock8: {}
// CHECK:STDOUT: typeBlock9: {}
// CHECK:STDOUT: typeBlock10: {}
// CHECK:STDOUT: typeBlock11:
// CHECK:STDOUT: typeBlock1:
// CHECK:STDOUT: 0: type1
// CHECK:STDOUT: 1: type1
// CHECK:STDOUT: insts:
@@ -57,7 +43,7 @@ fn Foo(n: ()) -> ((), ()) {
// CHECK:STDOUT: 'inst+5': {kind: BindName, arg0: bindName0, arg1: inst+4, type: type1}
// CHECK:STDOUT: 'inst+6': {kind: TupleLiteral, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+7': {kind: TupleLiteral, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+8': {kind: TupleType, arg0: typeBlock4, type: typeTypeType}
// CHECK:STDOUT: 'inst+8': {kind: TupleType, arg0: typeBlock1, type: typeTypeType}
// CHECK:STDOUT: 'inst+9': {kind: TupleLiteral, arg0: block4, type: type2}
// CHECK:STDOUT: 'inst+10': {kind: Converted, arg0: inst+6, arg1: inst+1, type: typeTypeType}
// CHECK:STDOUT: 'inst+11': {kind: Converted, arg0: inst+7, arg1: inst+1, type: typeTypeType}
@@ -78,7 +64,7 @@ fn Foo(n: ()) -> ((), ()) {
// CHECK:STDOUT: 'inst+26': {kind: TupleInit, arg0: empty, arg1: inst+25, type: type1}
// CHECK:STDOUT: 'inst+27': {kind: Converted, arg0: inst+19, arg1: inst+26, type: type1}
// CHECK:STDOUT: 'inst+28': {kind: TupleInit, arg0: block10, arg1: inst+13, type: type2}
// CHECK:STDOUT: 'inst+29': {kind: TupleValue, arg0: block12, type: type2}
// CHECK:STDOUT: 'inst+29': {kind: TupleValue, arg0: block11, type: type2}
// CHECK:STDOUT: 'inst+30': {kind: Converted, arg0: inst+20, arg1: inst+28, type: type2}
// CHECK:STDOUT: 'inst+31': {kind: ReturnExpr, arg0: inst+30, arg1: inst+13}
// CHECK:STDOUT: constant_values:
@@ -144,11 +130,10 @@ fn Foo(n: ()) -> ((), ()) {
// CHECK:STDOUT: block10:
// CHECK:STDOUT: 0: inst+24
// CHECK:STDOUT: 1: inst+27
// CHECK:STDOUT: block11: {}
// CHECK:STDOUT: block12:
// CHECK:STDOUT: block11:
// CHECK:STDOUT: 0: inst+23
// CHECK:STDOUT: 1: inst+23
// CHECK:STDOUT: block13:
// CHECK:STDOUT: block12:
// CHECK:STDOUT: 0: inst+0
// CHECK:STDOUT: 1: inst+14
// CHECK:STDOUT: ...
+5 -20
View File
@@ -31,21 +31,7 @@ fn Foo(n: ()) -> ((), ()) {
// CHECK:STDOUT: type4: {constant: template inst+17, value_rep: {kind: copy, type: type4}}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: typeBlock0: {}
// CHECK:STDOUT: typeBlock1: {}
// CHECK:STDOUT: typeBlock2: {}
// CHECK:STDOUT: typeBlock3: {}
// CHECK:STDOUT: typeBlock4:
// CHECK:STDOUT: 0: type1
// CHECK:STDOUT: 1: type1
// CHECK:STDOUT: typeBlock5: {}
// CHECK:STDOUT: typeBlock6: {}
// CHECK:STDOUT: typeBlock7:
// CHECK:STDOUT: 0: type1
// CHECK:STDOUT: 1: type1
// CHECK:STDOUT: typeBlock8: {}
// CHECK:STDOUT: typeBlock9: {}
// CHECK:STDOUT: typeBlock10: {}
// CHECK:STDOUT: typeBlock11:
// CHECK:STDOUT: typeBlock1:
// CHECK:STDOUT: 0: type1
// CHECK:STDOUT: 1: type1
// CHECK:STDOUT: insts:
@@ -57,7 +43,7 @@ fn Foo(n: ()) -> ((), ()) {
// CHECK:STDOUT: 'inst+5': {kind: BindName, arg0: bindName0, arg1: inst+4, type: type1}
// CHECK:STDOUT: 'inst+6': {kind: TupleLiteral, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+7': {kind: TupleLiteral, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+8': {kind: TupleType, arg0: typeBlock4, type: typeTypeType}
// CHECK:STDOUT: 'inst+8': {kind: TupleType, arg0: typeBlock1, type: typeTypeType}
// CHECK:STDOUT: 'inst+9': {kind: TupleLiteral, arg0: block4, type: type2}
// CHECK:STDOUT: 'inst+10': {kind: Converted, arg0: inst+6, arg1: inst+1, type: typeTypeType}
// CHECK:STDOUT: 'inst+11': {kind: Converted, arg0: inst+7, arg1: inst+1, type: typeTypeType}
@@ -78,7 +64,7 @@ fn Foo(n: ()) -> ((), ()) {
// CHECK:STDOUT: 'inst+26': {kind: TupleInit, arg0: empty, arg1: inst+25, type: type1}
// CHECK:STDOUT: 'inst+27': {kind: Converted, arg0: inst+19, arg1: inst+26, type: type1}
// CHECK:STDOUT: 'inst+28': {kind: TupleInit, arg0: block10, arg1: inst+13, type: type2}
// CHECK:STDOUT: 'inst+29': {kind: TupleValue, arg0: block12, type: type2}
// CHECK:STDOUT: 'inst+29': {kind: TupleValue, arg0: block11, type: type2}
// CHECK:STDOUT: 'inst+30': {kind: Converted, arg0: inst+20, arg1: inst+28, type: type2}
// CHECK:STDOUT: 'inst+31': {kind: ReturnExpr, arg0: inst+30, arg1: inst+13}
// CHECK:STDOUT: constant_values:
@@ -144,11 +130,10 @@ fn Foo(n: ()) -> ((), ()) {
// CHECK:STDOUT: block10:
// CHECK:STDOUT: 0: inst+24
// CHECK:STDOUT: 1: inst+27
// CHECK:STDOUT: block11: {}
// CHECK:STDOUT: block12:
// CHECK:STDOUT: block11:
// CHECK:STDOUT: 0: inst+23
// CHECK:STDOUT: 1: inst+23
// CHECK:STDOUT: block13:
// CHECK:STDOUT: block12:
// CHECK:STDOUT: 0: inst+0
// CHECK:STDOUT: 1: inst+14
// CHECK:STDOUT: ...
+6 -8
View File
@@ -62,9 +62,7 @@ fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.5: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.6: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.7: f64 = float_literal +Inf [template]
// CHECK:STDOUT: %.8: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.9: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.10: f64 = float_literal NaN [template]
// CHECK:STDOUT: %.8: f64 = float_literal NaN [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -99,11 +97,11 @@ fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc9_27.2: f64 = converted %float.div.loc9, %.loc9_27.1 [template = constants.%.7]
// CHECK:STDOUT: %b.loc9: f64 = bind_name b, %.loc9_27.2
// CHECK:STDOUT: %Div.ref.loc10: Div = name_ref Div, %Div.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc10_18: f64 = float_literal 0 [template = constants.%.8]
// CHECK:STDOUT: %.loc10_23: f64 = float_literal 0 [template = constants.%.9]
// CHECK:STDOUT: %float.div.loc10: init f64 = call %Div.ref.loc10(%.loc10_18, %.loc10_23) [template = constants.%.10]
// CHECK:STDOUT: %.loc10_27.1: f64 = value_of_initializer %float.div.loc10 [template = constants.%.10]
// CHECK:STDOUT: %.loc10_27.2: f64 = converted %float.div.loc10, %.loc10_27.1 [template = constants.%.10]
// CHECK:STDOUT: %.loc10_18: f64 = float_literal 0 [template = constants.%.6]
// CHECK:STDOUT: %.loc10_23: f64 = float_literal 0 [template = constants.%.6]
// CHECK:STDOUT: %float.div.loc10: init f64 = call %Div.ref.loc10(%.loc10_18, %.loc10_23) [template = constants.%.8]
// CHECK:STDOUT: %.loc10_27.1: f64 = value_of_initializer %float.div.loc10 [template = constants.%.8]
// CHECK:STDOUT: %.loc10_27.2: f64 = converted %float.div.loc10, %.loc10_27.1 [template = constants.%.8]
// CHECK:STDOUT: %c: f64 = bind_name c, %.loc10_27.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
+12 -14
View File
@@ -42,11 +42,9 @@ fn WrongResult(a: f64, b: f64) -> f64 = "float.eq";
// CHECK:STDOUT: %struct.2: F = struct_value () [template]
// CHECK:STDOUT: %.3: type = ptr_type {} [template]
// CHECK:STDOUT: %.4: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.5: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.6: bool = bool_literal true [template]
// CHECK:STDOUT: %.7: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.8: f64 = float_literal 2 [template]
// CHECK:STDOUT: %.9: bool = bool_literal false [template]
// CHECK:STDOUT: %.5: bool = bool_literal true [template]
// CHECK:STDOUT: %.6: f64 = float_literal 2 [template]
// CHECK:STDOUT: %.7: bool = bool_literal false [template]
// CHECK:STDOUT: %RuntimeCall: type = fn_type @RuntimeCall [template]
// CHECK:STDOUT: %struct.3: RuntimeCall = struct_value () [template]
// CHECK:STDOUT: }
@@ -104,10 +102,10 @@ fn WrongResult(a: f64, b: f64) -> f64 = "float.eq";
// CHECK:STDOUT: %true_.ref: True = name_ref true_, %true_
// CHECK:STDOUT: %Eq.ref.loc8: Eq = name_ref Eq, file.%Eq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc8_19: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc8_24: f64 = float_literal 1 [template = constants.%.5]
// CHECK:STDOUT: %float.eq.loc8: init bool = call %Eq.ref.loc8(%.loc8_19, %.loc8_24) [template = constants.%.6]
// CHECK:STDOUT: %.loc8_13.1: bool = value_of_initializer %float.eq.loc8 [template = constants.%.6]
// CHECK:STDOUT: %.loc8_13.2: bool = converted %float.eq.loc8, %.loc8_13.1 [template = constants.%.6]
// CHECK:STDOUT: %.loc8_24: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.eq.loc8: init bool = call %Eq.ref.loc8(%.loc8_19, %.loc8_24) [template = constants.%.5]
// CHECK:STDOUT: %.loc8_13.1: bool = value_of_initializer %float.eq.loc8 [template = constants.%.5]
// CHECK:STDOUT: %.loc8_13.2: bool = converted %float.eq.loc8, %.loc8_13.1 [template = constants.%.5]
// CHECK:STDOUT: if %.loc8_13.2 br !if.expr.then.loc8 else br !if.expr.else.loc8
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc8:
@@ -122,11 +120,11 @@ fn WrongResult(a: f64, b: f64) -> f64 = "float.eq";
// CHECK:STDOUT: %.loc8_13.3: type = block_arg !if.expr.result.loc8 [template = constants.%True]
// CHECK:STDOUT: %false_.ref: False = name_ref false_, %false_
// CHECK:STDOUT: %Eq.ref.loc9: Eq = name_ref Eq, file.%Eq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc9_20: f64 = float_literal 1 [template = constants.%.7]
// CHECK:STDOUT: %.loc9_25: f64 = float_literal 2 [template = constants.%.8]
// CHECK:STDOUT: %float.eq.loc9: init bool = call %Eq.ref.loc9(%.loc9_20, %.loc9_25) [template = constants.%.9]
// CHECK:STDOUT: %.loc9_14.1: bool = value_of_initializer %float.eq.loc9 [template = constants.%.9]
// CHECK:STDOUT: %.loc9_14.2: bool = converted %float.eq.loc9, %.loc9_14.1 [template = constants.%.9]
// CHECK:STDOUT: %.loc9_20: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc9_25: f64 = float_literal 2 [template = constants.%.6]
// CHECK:STDOUT: %float.eq.loc9: init bool = call %Eq.ref.loc9(%.loc9_20, %.loc9_25) [template = constants.%.7]
// CHECK:STDOUT: %.loc9_14.1: bool = value_of_initializer %float.eq.loc9 [template = constants.%.7]
// CHECK:STDOUT: %.loc9_14.2: bool = converted %float.eq.loc9, %.loc9_14.1 [template = constants.%.7]
// CHECK:STDOUT: if %.loc9_14.2 br !if.expr.then.loc9 else br !if.expr.else.loc9
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc9:
+23 -31
View File
@@ -41,17 +41,9 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.4: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.5: f64 = float_literal 2 [template]
// CHECK:STDOUT: %.6: bool = bool_literal false [template]
// CHECK:STDOUT: %.7: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.8: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.9: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.10: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.11: bool = bool_literal true [template]
// CHECK:STDOUT: %.12: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.13: f64 = float_literal -1 [template]
// CHECK:STDOUT: %.14: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.15: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.16: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.17: f64 = float_literal -1 [template]
// CHECK:STDOUT: %.7: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.8: bool = bool_literal true [template]
// CHECK:STDOUT: %.9: f64 = float_literal -1 [template]
// CHECK:STDOUT: %RuntimeCall: type = fn_type @RuntimeCall [template]
// CHECK:STDOUT: %struct.4: RuntimeCall = struct_value () [template]
// CHECK:STDOUT: }
@@ -135,8 +127,8 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc9_14.3: type = block_arg !if.expr.result.loc9 [template = constants.%False]
// CHECK:STDOUT: %false_.ref.loc10: False = name_ref false_, %false_
// CHECK:STDOUT: %Greater.ref.loc10: Greater = name_ref Greater, file.%Greater.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc10_25: f64 = float_literal 1 [template = constants.%.7]
// CHECK:STDOUT: %.loc10_30: f64 = float_literal 1 [template = constants.%.8]
// CHECK:STDOUT: %.loc10_25: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc10_30: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.greater.loc10: init bool = call %Greater.ref.loc10(%.loc10_25, %.loc10_30) [template = constants.%.6]
// CHECK:STDOUT: %.loc10_14.1: bool = value_of_initializer %float.greater.loc10 [template = constants.%.6]
// CHECK:STDOUT: %.loc10_14.2: bool = converted %float.greater.loc10, %.loc10_14.1 [template = constants.%.6]
@@ -154,11 +146,11 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc10_14.3: type = block_arg !if.expr.result.loc10 [template = constants.%False]
// CHECK:STDOUT: %true_.ref.loc11: True = name_ref true_, %true_
// CHECK:STDOUT: %Greater.ref.loc11: Greater = name_ref Greater, file.%Greater.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc11_24: f64 = float_literal 1 [template = constants.%.9]
// CHECK:STDOUT: %.loc11_29: f64 = float_literal 0 [template = constants.%.10]
// CHECK:STDOUT: %float.greater.loc11: init bool = call %Greater.ref.loc11(%.loc11_24, %.loc11_29) [template = constants.%.11]
// CHECK:STDOUT: %.loc11_13.1: bool = value_of_initializer %float.greater.loc11 [template = constants.%.11]
// CHECK:STDOUT: %.loc11_13.2: bool = converted %float.greater.loc11, %.loc11_13.1 [template = constants.%.11]
// CHECK:STDOUT: %.loc11_24: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc11_29: f64 = float_literal 0 [template = constants.%.7]
// CHECK:STDOUT: %float.greater.loc11: init bool = call %Greater.ref.loc11(%.loc11_24, %.loc11_29) [template = constants.%.8]
// CHECK:STDOUT: %.loc11_13.1: bool = value_of_initializer %float.greater.loc11 [template = constants.%.8]
// CHECK:STDOUT: %.loc11_13.2: bool = converted %float.greater.loc11, %.loc11_13.1 [template = constants.%.8]
// CHECK:STDOUT: if %.loc11_13.2 br !if.expr.then.loc11 else br !if.expr.else.loc11
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc11:
@@ -174,11 +166,11 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %false_.ref.loc12: False = name_ref false_, %false_
// CHECK:STDOUT: %Greater.ref.loc12: Greater = name_ref Greater, file.%Greater.decl [template = constants.%struct.1]
// CHECK:STDOUT: %Negate.ref.loc12: Negate = name_ref Negate, file.%Negate.decl [template = constants.%struct.2]
// CHECK:STDOUT: %.loc12_32: f64 = float_literal 1 [template = constants.%.12]
// CHECK:STDOUT: %float.negate.loc12: init f64 = call %Negate.ref.loc12(%.loc12_32) [template = constants.%.13]
// CHECK:STDOUT: %.loc12_38: f64 = float_literal 0 [template = constants.%.14]
// CHECK:STDOUT: %.loc12_24.1: f64 = value_of_initializer %float.negate.loc12 [template = constants.%.13]
// CHECK:STDOUT: %.loc12_24.2: f64 = converted %float.negate.loc12, %.loc12_24.1 [template = constants.%.13]
// CHECK:STDOUT: %.loc12_32: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.negate.loc12: init f64 = call %Negate.ref.loc12(%.loc12_32) [template = constants.%.9]
// CHECK:STDOUT: %.loc12_38: f64 = float_literal 0 [template = constants.%.7]
// CHECK:STDOUT: %.loc12_24.1: f64 = value_of_initializer %float.negate.loc12 [template = constants.%.9]
// CHECK:STDOUT: %.loc12_24.2: f64 = converted %float.negate.loc12, %.loc12_24.1 [template = constants.%.9]
// CHECK:STDOUT: %float.greater.loc12: init bool = call %Greater.ref.loc12(%.loc12_24.2, %.loc12_38) [template = constants.%.6]
// CHECK:STDOUT: %.loc12_14.1: bool = value_of_initializer %float.greater.loc12 [template = constants.%.6]
// CHECK:STDOUT: %.loc12_14.2: bool = converted %float.greater.loc12, %.loc12_14.1 [template = constants.%.6]
@@ -196,15 +188,15 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc12_14.3: type = block_arg !if.expr.result.loc12 [template = constants.%False]
// CHECK:STDOUT: %true_.ref.loc13: True = name_ref true_, %true_
// CHECK:STDOUT: %Greater.ref.loc13: Greater = name_ref Greater, file.%Greater.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc13_24: f64 = float_literal 0 [template = constants.%.15]
// CHECK:STDOUT: %.loc13_24: f64 = float_literal 0 [template = constants.%.7]
// CHECK:STDOUT: %Negate.ref.loc13: Negate = name_ref Negate, file.%Negate.decl [template = constants.%struct.2]
// CHECK:STDOUT: %.loc13_36: f64 = float_literal 1 [template = constants.%.16]
// CHECK:STDOUT: %float.negate.loc13: init f64 = call %Negate.ref.loc13(%.loc13_36) [template = constants.%.17]
// CHECK:STDOUT: %.loc13_23.1: f64 = value_of_initializer %float.negate.loc13 [template = constants.%.17]
// CHECK:STDOUT: %.loc13_23.2: f64 = converted %float.negate.loc13, %.loc13_23.1 [template = constants.%.17]
// CHECK:STDOUT: %float.greater.loc13: init bool = call %Greater.ref.loc13(%.loc13_24, %.loc13_23.2) [template = constants.%.11]
// CHECK:STDOUT: %.loc13_13.1: bool = value_of_initializer %float.greater.loc13 [template = constants.%.11]
// CHECK:STDOUT: %.loc13_13.2: bool = converted %float.greater.loc13, %.loc13_13.1 [template = constants.%.11]
// CHECK:STDOUT: %.loc13_36: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.negate.loc13: init f64 = call %Negate.ref.loc13(%.loc13_36) [template = constants.%.9]
// CHECK:STDOUT: %.loc13_23.1: f64 = value_of_initializer %float.negate.loc13 [template = constants.%.9]
// CHECK:STDOUT: %.loc13_23.2: f64 = converted %float.negate.loc13, %.loc13_23.1 [template = constants.%.9]
// CHECK:STDOUT: %float.greater.loc13: init bool = call %Greater.ref.loc13(%.loc13_24, %.loc13_23.2) [template = constants.%.8]
// CHECK:STDOUT: %.loc13_13.1: bool = value_of_initializer %float.greater.loc13 [template = constants.%.8]
// CHECK:STDOUT: %.loc13_13.2: bool = converted %float.greater.loc13, %.loc13_13.1 [template = constants.%.8]
// CHECK:STDOUT: if %.loc13_13.2 br !if.expr.then.loc13 else br !if.expr.else.loc13
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc13:
+26 -34
View File
@@ -41,17 +41,9 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.4: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.5: f64 = float_literal 2 [template]
// CHECK:STDOUT: %.6: bool = bool_literal false [template]
// CHECK:STDOUT: %.7: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.8: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.9: bool = bool_literal true [template]
// CHECK:STDOUT: %.10: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.11: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.12: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.13: f64 = float_literal -1 [template]
// CHECK:STDOUT: %.14: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.15: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.16: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.17: f64 = float_literal -1 [template]
// CHECK:STDOUT: %.7: bool = bool_literal true [template]
// CHECK:STDOUT: %.8: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.9: f64 = float_literal -1 [template]
// CHECK:STDOUT: %RuntimeCall: type = fn_type @RuntimeCall [template]
// CHECK:STDOUT: %struct.4: RuntimeCall = struct_value () [template]
// CHECK:STDOUT: }
@@ -135,11 +127,11 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc9_14.3: type = block_arg !if.expr.result.loc9 [template = constants.%False]
// CHECK:STDOUT: %true_.ref.loc10: True = name_ref true_, %true_
// CHECK:STDOUT: %GreaterEq.ref.loc10: GreaterEq = name_ref GreaterEq, file.%GreaterEq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc10_26: f64 = float_literal 1 [template = constants.%.7]
// CHECK:STDOUT: %.loc10_31: f64 = float_literal 1 [template = constants.%.8]
// CHECK:STDOUT: %float.greater_eq.loc10: init bool = call %GreaterEq.ref.loc10(%.loc10_26, %.loc10_31) [template = constants.%.9]
// CHECK:STDOUT: %.loc10_13.1: bool = value_of_initializer %float.greater_eq.loc10 [template = constants.%.9]
// CHECK:STDOUT: %.loc10_13.2: bool = converted %float.greater_eq.loc10, %.loc10_13.1 [template = constants.%.9]
// CHECK:STDOUT: %.loc10_26: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc10_31: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.greater_eq.loc10: init bool = call %GreaterEq.ref.loc10(%.loc10_26, %.loc10_31) [template = constants.%.7]
// CHECK:STDOUT: %.loc10_13.1: bool = value_of_initializer %float.greater_eq.loc10 [template = constants.%.7]
// CHECK:STDOUT: %.loc10_13.2: bool = converted %float.greater_eq.loc10, %.loc10_13.1 [template = constants.%.7]
// CHECK:STDOUT: if %.loc10_13.2 br !if.expr.then.loc10 else br !if.expr.else.loc10
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc10:
@@ -154,11 +146,11 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc10_13.3: type = block_arg !if.expr.result.loc10 [template = constants.%True]
// CHECK:STDOUT: %true_.ref.loc11: True = name_ref true_, %true_
// CHECK:STDOUT: %GreaterEq.ref.loc11: GreaterEq = name_ref GreaterEq, file.%GreaterEq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc11_26: f64 = float_literal 1 [template = constants.%.10]
// CHECK:STDOUT: %.loc11_31: f64 = float_literal 0 [template = constants.%.11]
// CHECK:STDOUT: %float.greater_eq.loc11: init bool = call %GreaterEq.ref.loc11(%.loc11_26, %.loc11_31) [template = constants.%.9]
// CHECK:STDOUT: %.loc11_13.1: bool = value_of_initializer %float.greater_eq.loc11 [template = constants.%.9]
// CHECK:STDOUT: %.loc11_13.2: bool = converted %float.greater_eq.loc11, %.loc11_13.1 [template = constants.%.9]
// CHECK:STDOUT: %.loc11_26: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc11_31: f64 = float_literal 0 [template = constants.%.8]
// CHECK:STDOUT: %float.greater_eq.loc11: init bool = call %GreaterEq.ref.loc11(%.loc11_26, %.loc11_31) [template = constants.%.7]
// CHECK:STDOUT: %.loc11_13.1: bool = value_of_initializer %float.greater_eq.loc11 [template = constants.%.7]
// CHECK:STDOUT: %.loc11_13.2: bool = converted %float.greater_eq.loc11, %.loc11_13.1 [template = constants.%.7]
// CHECK:STDOUT: if %.loc11_13.2 br !if.expr.then.loc11 else br !if.expr.else.loc11
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc11:
@@ -174,11 +166,11 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %false_.ref.loc12: False = name_ref false_, %false_
// CHECK:STDOUT: %GreaterEq.ref.loc12: GreaterEq = name_ref GreaterEq, file.%GreaterEq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %Negate.ref.loc12: Negate = name_ref Negate, file.%Negate.decl [template = constants.%struct.2]
// CHECK:STDOUT: %.loc12_34: f64 = float_literal 1 [template = constants.%.12]
// CHECK:STDOUT: %float.negate.loc12: init f64 = call %Negate.ref.loc12(%.loc12_34) [template = constants.%.13]
// CHECK:STDOUT: %.loc12_40: f64 = float_literal 0 [template = constants.%.14]
// CHECK:STDOUT: %.loc12_26.1: f64 = value_of_initializer %float.negate.loc12 [template = constants.%.13]
// CHECK:STDOUT: %.loc12_26.2: f64 = converted %float.negate.loc12, %.loc12_26.1 [template = constants.%.13]
// CHECK:STDOUT: %.loc12_34: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.negate.loc12: init f64 = call %Negate.ref.loc12(%.loc12_34) [template = constants.%.9]
// CHECK:STDOUT: %.loc12_40: f64 = float_literal 0 [template = constants.%.8]
// CHECK:STDOUT: %.loc12_26.1: f64 = value_of_initializer %float.negate.loc12 [template = constants.%.9]
// CHECK:STDOUT: %.loc12_26.2: f64 = converted %float.negate.loc12, %.loc12_26.1 [template = constants.%.9]
// CHECK:STDOUT: %float.greater_eq.loc12: init bool = call %GreaterEq.ref.loc12(%.loc12_26.2, %.loc12_40) [template = constants.%.6]
// CHECK:STDOUT: %.loc12_14.1: bool = value_of_initializer %float.greater_eq.loc12 [template = constants.%.6]
// CHECK:STDOUT: %.loc12_14.2: bool = converted %float.greater_eq.loc12, %.loc12_14.1 [template = constants.%.6]
@@ -196,15 +188,15 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc12_14.3: type = block_arg !if.expr.result.loc12 [template = constants.%False]
// CHECK:STDOUT: %true_.ref.loc13: True = name_ref true_, %true_
// CHECK:STDOUT: %GreaterEq.ref.loc13: GreaterEq = name_ref GreaterEq, file.%GreaterEq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc13_26: f64 = float_literal 0 [template = constants.%.15]
// CHECK:STDOUT: %.loc13_26: f64 = float_literal 0 [template = constants.%.8]
// CHECK:STDOUT: %Negate.ref.loc13: Negate = name_ref Negate, file.%Negate.decl [template = constants.%struct.2]
// CHECK:STDOUT: %.loc13_38: f64 = float_literal 1 [template = constants.%.16]
// CHECK:STDOUT: %float.negate.loc13: init f64 = call %Negate.ref.loc13(%.loc13_38) [template = constants.%.17]
// CHECK:STDOUT: %.loc13_25.1: f64 = value_of_initializer %float.negate.loc13 [template = constants.%.17]
// CHECK:STDOUT: %.loc13_25.2: f64 = converted %float.negate.loc13, %.loc13_25.1 [template = constants.%.17]
// CHECK:STDOUT: %float.greater_eq.loc13: init bool = call %GreaterEq.ref.loc13(%.loc13_26, %.loc13_25.2) [template = constants.%.9]
// CHECK:STDOUT: %.loc13_13.1: bool = value_of_initializer %float.greater_eq.loc13 [template = constants.%.9]
// CHECK:STDOUT: %.loc13_13.2: bool = converted %float.greater_eq.loc13, %.loc13_13.1 [template = constants.%.9]
// CHECK:STDOUT: %.loc13_38: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.negate.loc13: init f64 = call %Negate.ref.loc13(%.loc13_38) [template = constants.%.9]
// CHECK:STDOUT: %.loc13_25.1: f64 = value_of_initializer %float.negate.loc13 [template = constants.%.9]
// CHECK:STDOUT: %.loc13_25.2: f64 = converted %float.negate.loc13, %.loc13_25.1 [template = constants.%.9]
// CHECK:STDOUT: %float.greater_eq.loc13: init bool = call %GreaterEq.ref.loc13(%.loc13_26, %.loc13_25.2) [template = constants.%.7]
// CHECK:STDOUT: %.loc13_13.1: bool = value_of_initializer %float.greater_eq.loc13 [template = constants.%.7]
// CHECK:STDOUT: %.loc13_13.2: bool = converted %float.greater_eq.loc13, %.loc13_13.1 [template = constants.%.7]
// CHECK:STDOUT: if %.loc13_13.2 br !if.expr.then.loc13 else br !if.expr.else.loc13
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc13:
+26 -34
View File
@@ -41,17 +41,9 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.4: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.5: f64 = float_literal 2 [template]
// CHECK:STDOUT: %.6: bool = bool_literal true [template]
// CHECK:STDOUT: %.7: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.8: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.9: bool = bool_literal false [template]
// CHECK:STDOUT: %.10: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.11: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.12: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.13: f64 = float_literal -1 [template]
// CHECK:STDOUT: %.14: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.15: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.16: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.17: f64 = float_literal -1 [template]
// CHECK:STDOUT: %.7: bool = bool_literal false [template]
// CHECK:STDOUT: %.8: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.9: f64 = float_literal -1 [template]
// CHECK:STDOUT: %RuntimeCall: type = fn_type @RuntimeCall [template]
// CHECK:STDOUT: %struct.4: RuntimeCall = struct_value () [template]
// CHECK:STDOUT: }
@@ -135,11 +127,11 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc9_13.3: type = block_arg !if.expr.result.loc9 [template = constants.%True]
// CHECK:STDOUT: %false_.ref.loc10: False = name_ref false_, %false_
// CHECK:STDOUT: %Less.ref.loc10: Less = name_ref Less, file.%Less.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc10_22: f64 = float_literal 1 [template = constants.%.7]
// CHECK:STDOUT: %.loc10_27: f64 = float_literal 1 [template = constants.%.8]
// CHECK:STDOUT: %float.less.loc10: init bool = call %Less.ref.loc10(%.loc10_22, %.loc10_27) [template = constants.%.9]
// CHECK:STDOUT: %.loc10_14.1: bool = value_of_initializer %float.less.loc10 [template = constants.%.9]
// CHECK:STDOUT: %.loc10_14.2: bool = converted %float.less.loc10, %.loc10_14.1 [template = constants.%.9]
// CHECK:STDOUT: %.loc10_22: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc10_27: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.less.loc10: init bool = call %Less.ref.loc10(%.loc10_22, %.loc10_27) [template = constants.%.7]
// CHECK:STDOUT: %.loc10_14.1: bool = value_of_initializer %float.less.loc10 [template = constants.%.7]
// CHECK:STDOUT: %.loc10_14.2: bool = converted %float.less.loc10, %.loc10_14.1 [template = constants.%.7]
// CHECK:STDOUT: if %.loc10_14.2 br !if.expr.then.loc10 else br !if.expr.else.loc10
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc10:
@@ -154,11 +146,11 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc10_14.3: type = block_arg !if.expr.result.loc10 [template = constants.%False]
// CHECK:STDOUT: %false_.ref.loc11: False = name_ref false_, %false_
// CHECK:STDOUT: %Less.ref.loc11: Less = name_ref Less, file.%Less.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc11_22: f64 = float_literal 1 [template = constants.%.10]
// CHECK:STDOUT: %.loc11_27: f64 = float_literal 0 [template = constants.%.11]
// CHECK:STDOUT: %float.less.loc11: init bool = call %Less.ref.loc11(%.loc11_22, %.loc11_27) [template = constants.%.9]
// CHECK:STDOUT: %.loc11_14.1: bool = value_of_initializer %float.less.loc11 [template = constants.%.9]
// CHECK:STDOUT: %.loc11_14.2: bool = converted %float.less.loc11, %.loc11_14.1 [template = constants.%.9]
// CHECK:STDOUT: %.loc11_22: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc11_27: f64 = float_literal 0 [template = constants.%.8]
// CHECK:STDOUT: %float.less.loc11: init bool = call %Less.ref.loc11(%.loc11_22, %.loc11_27) [template = constants.%.7]
// CHECK:STDOUT: %.loc11_14.1: bool = value_of_initializer %float.less.loc11 [template = constants.%.7]
// CHECK:STDOUT: %.loc11_14.2: bool = converted %float.less.loc11, %.loc11_14.1 [template = constants.%.7]
// CHECK:STDOUT: if %.loc11_14.2 br !if.expr.then.loc11 else br !if.expr.else.loc11
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc11:
@@ -174,11 +166,11 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %true_.ref.loc12: True = name_ref true_, %true_
// CHECK:STDOUT: %Less.ref.loc12: Less = name_ref Less, file.%Less.decl [template = constants.%struct.1]
// CHECK:STDOUT: %Negate.ref.loc12: Negate = name_ref Negate, file.%Negate.decl [template = constants.%struct.2]
// CHECK:STDOUT: %.loc12_28: f64 = float_literal 1 [template = constants.%.12]
// CHECK:STDOUT: %float.negate.loc12: init f64 = call %Negate.ref.loc12(%.loc12_28) [template = constants.%.13]
// CHECK:STDOUT: %.loc12_34: f64 = float_literal 0 [template = constants.%.14]
// CHECK:STDOUT: %.loc12_20.1: f64 = value_of_initializer %float.negate.loc12 [template = constants.%.13]
// CHECK:STDOUT: %.loc12_20.2: f64 = converted %float.negate.loc12, %.loc12_20.1 [template = constants.%.13]
// CHECK:STDOUT: %.loc12_28: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.negate.loc12: init f64 = call %Negate.ref.loc12(%.loc12_28) [template = constants.%.9]
// CHECK:STDOUT: %.loc12_34: f64 = float_literal 0 [template = constants.%.8]
// CHECK:STDOUT: %.loc12_20.1: f64 = value_of_initializer %float.negate.loc12 [template = constants.%.9]
// CHECK:STDOUT: %.loc12_20.2: f64 = converted %float.negate.loc12, %.loc12_20.1 [template = constants.%.9]
// CHECK:STDOUT: %float.less.loc12: init bool = call %Less.ref.loc12(%.loc12_20.2, %.loc12_34) [template = constants.%.6]
// CHECK:STDOUT: %.loc12_13.1: bool = value_of_initializer %float.less.loc12 [template = constants.%.6]
// CHECK:STDOUT: %.loc12_13.2: bool = converted %float.less.loc12, %.loc12_13.1 [template = constants.%.6]
@@ -196,15 +188,15 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc12_13.3: type = block_arg !if.expr.result.loc12 [template = constants.%True]
// CHECK:STDOUT: %false_.ref.loc13: False = name_ref false_, %false_
// CHECK:STDOUT: %Less.ref.loc13: Less = name_ref Less, file.%Less.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc13_22: f64 = float_literal 0 [template = constants.%.15]
// CHECK:STDOUT: %.loc13_22: f64 = float_literal 0 [template = constants.%.8]
// CHECK:STDOUT: %Negate.ref.loc13: Negate = name_ref Negate, file.%Negate.decl [template = constants.%struct.2]
// CHECK:STDOUT: %.loc13_34: f64 = float_literal 1 [template = constants.%.16]
// CHECK:STDOUT: %float.negate.loc13: init f64 = call %Negate.ref.loc13(%.loc13_34) [template = constants.%.17]
// CHECK:STDOUT: %.loc13_21.1: f64 = value_of_initializer %float.negate.loc13 [template = constants.%.17]
// CHECK:STDOUT: %.loc13_21.2: f64 = converted %float.negate.loc13, %.loc13_21.1 [template = constants.%.17]
// CHECK:STDOUT: %float.less.loc13: init bool = call %Less.ref.loc13(%.loc13_22, %.loc13_21.2) [template = constants.%.9]
// CHECK:STDOUT: %.loc13_14.1: bool = value_of_initializer %float.less.loc13 [template = constants.%.9]
// CHECK:STDOUT: %.loc13_14.2: bool = converted %float.less.loc13, %.loc13_14.1 [template = constants.%.9]
// CHECK:STDOUT: %.loc13_34: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.negate.loc13: init f64 = call %Negate.ref.loc13(%.loc13_34) [template = constants.%.9]
// CHECK:STDOUT: %.loc13_21.1: f64 = value_of_initializer %float.negate.loc13 [template = constants.%.9]
// CHECK:STDOUT: %.loc13_21.2: f64 = converted %float.negate.loc13, %.loc13_21.1 [template = constants.%.9]
// CHECK:STDOUT: %float.less.loc13: init bool = call %Less.ref.loc13(%.loc13_22, %.loc13_21.2) [template = constants.%.7]
// CHECK:STDOUT: %.loc13_14.1: bool = value_of_initializer %float.less.loc13 [template = constants.%.7]
// CHECK:STDOUT: %.loc13_14.2: bool = converted %float.less.loc13, %.loc13_14.1 [template = constants.%.7]
// CHECK:STDOUT: if %.loc13_14.2 br !if.expr.then.loc13 else br !if.expr.else.loc13
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc13:
+23 -31
View File
@@ -41,17 +41,9 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.4: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.5: f64 = float_literal 2 [template]
// CHECK:STDOUT: %.6: bool = bool_literal true [template]
// CHECK:STDOUT: %.7: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.8: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.9: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.10: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.11: bool = bool_literal false [template]
// CHECK:STDOUT: %.12: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.13: f64 = float_literal -1 [template]
// CHECK:STDOUT: %.14: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.15: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.16: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.17: f64 = float_literal -1 [template]
// CHECK:STDOUT: %.7: f64 = float_literal 0 [template]
// CHECK:STDOUT: %.8: bool = bool_literal false [template]
// CHECK:STDOUT: %.9: f64 = float_literal -1 [template]
// CHECK:STDOUT: %RuntimeCall: type = fn_type @RuntimeCall [template]
// CHECK:STDOUT: %struct.4: RuntimeCall = struct_value () [template]
// CHECK:STDOUT: }
@@ -135,8 +127,8 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc9_13.3: type = block_arg !if.expr.result.loc9 [template = constants.%True]
// CHECK:STDOUT: %true_.ref.loc10: True = name_ref true_, %true_
// CHECK:STDOUT: %LessEq.ref.loc10: LessEq = name_ref LessEq, file.%LessEq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc10_23: f64 = float_literal 1 [template = constants.%.7]
// CHECK:STDOUT: %.loc10_28: f64 = float_literal 1 [template = constants.%.8]
// CHECK:STDOUT: %.loc10_23: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc10_28: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.less_eq.loc10: init bool = call %LessEq.ref.loc10(%.loc10_23, %.loc10_28) [template = constants.%.6]
// CHECK:STDOUT: %.loc10_13.1: bool = value_of_initializer %float.less_eq.loc10 [template = constants.%.6]
// CHECK:STDOUT: %.loc10_13.2: bool = converted %float.less_eq.loc10, %.loc10_13.1 [template = constants.%.6]
@@ -154,11 +146,11 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc10_13.3: type = block_arg !if.expr.result.loc10 [template = constants.%True]
// CHECK:STDOUT: %false_.ref.loc11: False = name_ref false_, %false_
// CHECK:STDOUT: %LessEq.ref.loc11: LessEq = name_ref LessEq, file.%LessEq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc11_24: f64 = float_literal 1 [template = constants.%.9]
// CHECK:STDOUT: %.loc11_29: f64 = float_literal 0 [template = constants.%.10]
// CHECK:STDOUT: %float.less_eq.loc11: init bool = call %LessEq.ref.loc11(%.loc11_24, %.loc11_29) [template = constants.%.11]
// CHECK:STDOUT: %.loc11_14.1: bool = value_of_initializer %float.less_eq.loc11 [template = constants.%.11]
// CHECK:STDOUT: %.loc11_14.2: bool = converted %float.less_eq.loc11, %.loc11_14.1 [template = constants.%.11]
// CHECK:STDOUT: %.loc11_24: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc11_29: f64 = float_literal 0 [template = constants.%.7]
// CHECK:STDOUT: %float.less_eq.loc11: init bool = call %LessEq.ref.loc11(%.loc11_24, %.loc11_29) [template = constants.%.8]
// CHECK:STDOUT: %.loc11_14.1: bool = value_of_initializer %float.less_eq.loc11 [template = constants.%.8]
// CHECK:STDOUT: %.loc11_14.2: bool = converted %float.less_eq.loc11, %.loc11_14.1 [template = constants.%.8]
// CHECK:STDOUT: if %.loc11_14.2 br !if.expr.then.loc11 else br !if.expr.else.loc11
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc11:
@@ -174,11 +166,11 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %true_.ref.loc12: True = name_ref true_, %true_
// CHECK:STDOUT: %LessEq.ref.loc12: LessEq = name_ref LessEq, file.%LessEq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %Negate.ref.loc12: Negate = name_ref Negate, file.%Negate.decl [template = constants.%struct.2]
// CHECK:STDOUT: %.loc12_30: f64 = float_literal 1 [template = constants.%.12]
// CHECK:STDOUT: %float.negate.loc12: init f64 = call %Negate.ref.loc12(%.loc12_30) [template = constants.%.13]
// CHECK:STDOUT: %.loc12_36: f64 = float_literal 0 [template = constants.%.14]
// CHECK:STDOUT: %.loc12_22.1: f64 = value_of_initializer %float.negate.loc12 [template = constants.%.13]
// CHECK:STDOUT: %.loc12_22.2: f64 = converted %float.negate.loc12, %.loc12_22.1 [template = constants.%.13]
// CHECK:STDOUT: %.loc12_30: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.negate.loc12: init f64 = call %Negate.ref.loc12(%.loc12_30) [template = constants.%.9]
// CHECK:STDOUT: %.loc12_36: f64 = float_literal 0 [template = constants.%.7]
// CHECK:STDOUT: %.loc12_22.1: f64 = value_of_initializer %float.negate.loc12 [template = constants.%.9]
// CHECK:STDOUT: %.loc12_22.2: f64 = converted %float.negate.loc12, %.loc12_22.1 [template = constants.%.9]
// CHECK:STDOUT: %float.less_eq.loc12: init bool = call %LessEq.ref.loc12(%.loc12_22.2, %.loc12_36) [template = constants.%.6]
// CHECK:STDOUT: %.loc12_13.1: bool = value_of_initializer %float.less_eq.loc12 [template = constants.%.6]
// CHECK:STDOUT: %.loc12_13.2: bool = converted %float.less_eq.loc12, %.loc12_13.1 [template = constants.%.6]
@@ -196,15 +188,15 @@ fn RuntimeCall(a: f64, b: f64) -> bool {
// CHECK:STDOUT: %.loc12_13.3: type = block_arg !if.expr.result.loc12 [template = constants.%True]
// CHECK:STDOUT: %false_.ref.loc13: False = name_ref false_, %false_
// CHECK:STDOUT: %LessEq.ref.loc13: LessEq = name_ref LessEq, file.%LessEq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc13_24: f64 = float_literal 0 [template = constants.%.15]
// CHECK:STDOUT: %.loc13_24: f64 = float_literal 0 [template = constants.%.7]
// CHECK:STDOUT: %Negate.ref.loc13: Negate = name_ref Negate, file.%Negate.decl [template = constants.%struct.2]
// CHECK:STDOUT: %.loc13_36: f64 = float_literal 1 [template = constants.%.16]
// CHECK:STDOUT: %float.negate.loc13: init f64 = call %Negate.ref.loc13(%.loc13_36) [template = constants.%.17]
// CHECK:STDOUT: %.loc13_23.1: f64 = value_of_initializer %float.negate.loc13 [template = constants.%.17]
// CHECK:STDOUT: %.loc13_23.2: f64 = converted %float.negate.loc13, %.loc13_23.1 [template = constants.%.17]
// CHECK:STDOUT: %float.less_eq.loc13: init bool = call %LessEq.ref.loc13(%.loc13_24, %.loc13_23.2) [template = constants.%.11]
// CHECK:STDOUT: %.loc13_14.1: bool = value_of_initializer %float.less_eq.loc13 [template = constants.%.11]
// CHECK:STDOUT: %.loc13_14.2: bool = converted %float.less_eq.loc13, %.loc13_14.1 [template = constants.%.11]
// CHECK:STDOUT: %.loc13_36: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.negate.loc13: init f64 = call %Negate.ref.loc13(%.loc13_36) [template = constants.%.9]
// CHECK:STDOUT: %.loc13_23.1: f64 = value_of_initializer %float.negate.loc13 [template = constants.%.9]
// CHECK:STDOUT: %.loc13_23.2: f64 = converted %float.negate.loc13, %.loc13_23.1 [template = constants.%.9]
// CHECK:STDOUT: %float.less_eq.loc13: init bool = call %LessEq.ref.loc13(%.loc13_24, %.loc13_23.2) [template = constants.%.8]
// CHECK:STDOUT: %.loc13_14.1: bool = value_of_initializer %float.less_eq.loc13 [template = constants.%.8]
// CHECK:STDOUT: %.loc13_14.2: bool = converted %float.less_eq.loc13, %.loc13_14.1 [template = constants.%.8]
// CHECK:STDOUT: if %.loc13_14.2 br !if.expr.then.loc13 else br !if.expr.else.loc13
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc13:
+6 -8
View File
@@ -44,9 +44,7 @@ fn WrongResult(a: f64, b: f64) -> f64 = "float.neq";
// CHECK:STDOUT: %.4: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.5: f64 = float_literal 2 [template]
// CHECK:STDOUT: %.6: bool = bool_literal true [template]
// CHECK:STDOUT: %.7: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.8: f64 = float_literal 1 [template]
// CHECK:STDOUT: %.9: bool = bool_literal false [template]
// CHECK:STDOUT: %.7: bool = bool_literal false [template]
// CHECK:STDOUT: %RuntimeCall: type = fn_type @RuntimeCall [template]
// CHECK:STDOUT: %struct.3: RuntimeCall = struct_value () [template]
// CHECK:STDOUT: }
@@ -122,11 +120,11 @@ fn WrongResult(a: f64, b: f64) -> f64 = "float.neq";
// CHECK:STDOUT: %.loc8_13.3: type = block_arg !if.expr.result.loc8 [template = constants.%True]
// CHECK:STDOUT: %false_.ref: False = name_ref false_, %false_
// CHECK:STDOUT: %Neq.ref.loc9: Neq = name_ref Neq, file.%Neq.decl [template = constants.%struct.1]
// CHECK:STDOUT: %.loc9_21: f64 = float_literal 1 [template = constants.%.7]
// CHECK:STDOUT: %.loc9_26: f64 = float_literal 1 [template = constants.%.8]
// CHECK:STDOUT: %float.neq.loc9: init bool = call %Neq.ref.loc9(%.loc9_21, %.loc9_26) [template = constants.%.9]
// CHECK:STDOUT: %.loc9_14.1: bool = value_of_initializer %float.neq.loc9 [template = constants.%.9]
// CHECK:STDOUT: %.loc9_14.2: bool = converted %float.neq.loc9, %.loc9_14.1 [template = constants.%.9]
// CHECK:STDOUT: %.loc9_21: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc9_26: f64 = float_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %float.neq.loc9: init bool = call %Neq.ref.loc9(%.loc9_21, %.loc9_26) [template = constants.%.7]
// CHECK:STDOUT: %.loc9_14.1: bool = value_of_initializer %float.neq.loc9 [template = constants.%.7]
// CHECK:STDOUT: %.loc9_14.2: bool = converted %float.neq.loc9, %.loc9_14.1 [template = constants.%.7]
// CHECK:STDOUT: if %.loc9_14.2 br !if.expr.then.loc9 else br !if.expr.else.loc9
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then.loc9:
+2 -5
View File
@@ -21,11 +21,8 @@ var str2: String = "ab'\"c";
// CHECK:STDOUT: ints:
// CHECK:STDOUT: int0: 32
// CHECK:STDOUT: int1: 1
// CHECK:STDOUT: int2: 32
// CHECK:STDOUT: int3: 8
// CHECK:STDOUT: int4: 64
// CHECK:STDOUT: int5: 64
// CHECK:STDOUT: int6: 64
// CHECK:STDOUT: int2: 8
// CHECK:STDOUT: int3: 64
// CHECK:STDOUT: reals:
// CHECK:STDOUT: real0: 10*10^-1
// CHECK:STDOUT: real1: 8*10^7
+4 -2
View File
@@ -18,6 +18,7 @@ cc_library(
name = "block_value_store",
hdrs = ["block_value_store.h"],
deps = [
"//common:hashing",
"//toolchain/base:value_store",
"//toolchain/base:yaml",
"@llvm-project//llvm:Support",
@@ -68,6 +69,7 @@ cc_library(
":ids",
":inst_kind",
"//common:check",
"//common:hashing",
"//common:ostream",
"//common:struct_reflection",
"//toolchain/base:index_base",
@@ -82,11 +84,10 @@ cc_library(
"constant.cpp",
"file.cpp",
"function.cpp",
"inst_profile.cpp",
"inst_profile.h",
"name.cpp",
],
hdrs = [
"bind_name.h",
"builtin_function_kind.h",
"class.h",
"constant.h",
@@ -113,6 +114,7 @@ cc_library(
"//common:check",
"//common:enum_base",
"//common:error",
"//common:hashing",
"//toolchain/base:kind_switch",
"//toolchain/base:value_store",
"//toolchain/base:yaml",
+76
View File
@@ -0,0 +1,76 @@
// 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
#ifndef CARBON_TOOLCHAIN_SEM_IR_BIND_NAME_H_
#define CARBON_TOOLCHAIN_SEM_IR_BIND_NAME_H_
#include "common/hashing.h"
#include "toolchain/base/value_store.h"
#include "toolchain/sem_ir/ids.h"
namespace Carbon::SemIR {
struct BindNameInfo : public Printable<BindNameInfo> {
auto Print(llvm::raw_ostream& out) const -> void {
out << "{name: " << name_id << ", enclosing_scope: " << enclosing_scope_id
<< ", index: " << bind_index << "}";
}
// The name.
NameId name_id;
// The enclosing scope.
NameScopeId enclosing_scope_id;
// The index for a compile-time binding. Invalid for a runtime binding.
CompileTimeBindIndex bind_index;
};
// Hashing for BindNameInfo.
inline auto CarbonHashValue(const BindNameInfo& value, uint64_t seed)
-> HashCode {
Hasher hasher(seed);
hasher.Hash(value);
return static_cast<HashCode>(hasher);
}
// DenseMapInfo for BindNameInfo.
struct BindNameInfoDenseMapInfo {
static auto getEmptyKey() -> BindNameInfo {
return BindNameInfo{.name_id = NameId::Invalid,
.enclosing_scope_id = NameScopeId::Invalid,
.bind_index = CompileTimeBindIndex(
CompileTimeBindIndex::InvalidIndex - 1)};
}
static auto getTombstoneKey() -> BindNameInfo {
return BindNameInfo{.name_id = NameId::Invalid,
.enclosing_scope_id = NameScopeId::Invalid,
.bind_index = CompileTimeBindIndex(
CompileTimeBindIndex::InvalidIndex - 2)};
}
static auto getHashValue(const BindNameInfo& val) -> unsigned {
return static_cast<uint64_t>(HashValue(val));
}
static auto isEqual(const BindNameInfo& lhs, const BindNameInfo& rhs)
-> bool {
return std::memcmp(&lhs, &rhs, sizeof(BindNameInfo)) == 0;
}
};
// Value store for BindNameInfo. In addition to the regular ValueStore
// functionality, this can provide optional canonical IDs for BindNameInfos.
struct BindNameStore : public ValueStore<BindNameId> {
public:
// Convert an ID to a canonical ID. All calls to this with equivalent
// `BindNameInfo`s will return the same `BindNameId`.
auto MakeCanonical(BindNameId id) -> BindNameId {
return canonical_ids_.insert({Get(id), id}).first->second;
}
private:
llvm::DenseMap<BindNameInfo, BindNameId, BindNameInfoDenseMapInfo>
canonical_ids_;
};
} // namespace Carbon::SemIR
#endif // CARBON_TOOLCHAIN_SEM_IR_BIND_NAME_H_
+57
View File
@@ -7,6 +7,7 @@
#include <type_traits>
#include "common/hashing.h"
#include "llvm/ADT/DenseMap.h"
#include "toolchain/base/value_store.h"
#include "toolchain/base/yaml.h"
@@ -47,6 +48,25 @@ class BlockValueStore : public Yaml::Printable<BlockValueStore<IdT>> {
return values_.Get(id);
}
// Adds a block or finds an existing canonical block with the given content,
// and returns an ID to reference it.
auto AddCanonical(llvm::ArrayRef<ElementType> content) -> IdT {
auto [it, added] = canonical_blocks_.insert({{content}, IdT::Invalid});
if (added) {
auto id = Add(content);
it->first.data = Get(id);
it->second = id;
}
return it->second;
}
// Promotes an existing block ID to a canonical block ID, or returns an
// existing canonical block ID if the block was already added. The specified
// block must not be modified after this point.
auto MakeCanonical(IdT id) -> IdT {
return canonical_blocks_.insert({{Get(id)}, id}).first->second;
}
auto OutputYaml() const -> Yaml::OutputMapping {
return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
for (auto block_index : llvm::seq(values_.size())) {
@@ -82,6 +102,41 @@ class BlockValueStore : public Yaml::Printable<BlockValueStore<IdT>> {
}
private:
// A canonical block, for which we allocate a deduplicated ID.
struct CanonicalBlock {
// This is mutable so we can repoint it at the allocated data if insertion
// succeeds.
mutable llvm::ArrayRef<ElementType> data;
// See common/hashing.h.
friend auto CarbonHashValue(CanonicalBlock block, uint64_t seed)
-> HashCode {
Hasher hasher(seed);
hasher.HashSizedBytes(block.data);
return static_cast<HashCode>(hasher);
}
};
struct CanonicalBlockDenseMapInfo {
// Blocks whose data() points to the start of `SpecialData` are used to
// represent the special "empty" and "tombstone" states.
static constexpr ElementType SpecialData[1] = {ElementType::Invalid};
static auto getEmptyKey() -> CanonicalBlock {
return CanonicalBlock{
llvm::ArrayRef(SpecialData, static_cast<size_t>(0))};
}
static auto getTombstoneKey() -> CanonicalBlock {
return CanonicalBlock{llvm::ArrayRef(SpecialData, 1)};
}
static auto getHashValue(CanonicalBlock val) -> unsigned {
return static_cast<uint64_t>(HashValue(val));
}
static auto isEqual(CanonicalBlock lhs, CanonicalBlock rhs) -> bool {
return lhs.data == rhs.data && (lhs.data.data() == SpecialData) ==
(rhs.data.data() == SpecialData);
}
};
// Allocates an uninitialized array using our slab allocator.
auto AllocateUninitialized(std::size_t size)
-> llvm::MutableArrayRef<ElementType> {
@@ -103,6 +158,8 @@ class BlockValueStore : public Yaml::Printable<BlockValueStore<IdT>> {
llvm::BumpPtrAllocator* allocator_;
ValueStore<IdT> values_;
llvm::DenseMap<CanonicalBlock, IdT, CanonicalBlockDenseMapInfo>
canonical_blocks_;
};
} // namespace Carbon::SemIR
+14 -62
View File
@@ -4,73 +4,25 @@
#include "toolchain/sem_ir/constant.h"
#include "toolchain/sem_ir/inst_profile.h"
#include "toolchain/sem_ir/file.h"
namespace Carbon::SemIR {
auto ConstantStore::GetOrAdd(Inst inst, bool is_symbolic) -> ConstantId {
// Check that we're allowed to form this kind of constant.
switch (inst.kind().constant_kind()) {
case InstConstantKind::Never:
CARBON_FATAL() << "Should not form a constant from instruction " << inst;
break;
case InstConstantKind::SymbolicOnly:
CARBON_CHECK(is_symbolic)
<< "Should only form a symbolic constant from instruction " << inst;
break;
case InstConstantKind::Conditional:
break;
case InstConstantKind::Always:
CARBON_CHECK(!is_symbolic)
<< "Should only form a template constant from instruction " << inst;
break;
auto [it, added] = map_.insert({inst, ConstantId::Invalid});
if (added) {
auto inst_id = sem_ir_.insts().AddInNoBlock(LocIdAndInst::NoLoc(inst));
auto const_id = is_symbolic
? SemIR::ConstantId::ForSymbolicConstant(inst_id)
: SemIR::ConstantId::ForTemplateConstant(inst_id);
it->second = const_id;
sem_ir_.constant_values().Set(inst_id, const_id);
constants_.push_back(inst_id);
} else {
CARBON_CHECK(it->second != ConstantId::Invalid);
CARBON_CHECK(it->second.is_symbolic() == is_symbolic);
}
// Compute the instruction's profile.
ConstantNode node = {.inst = inst, .constant_id = ConstantId::NotConstant};
llvm::FoldingSetNodeID id;
node.Profile(id, constants_.getContext());
// Check if we have already created this constant.
void* insert_pos;
if (ConstantNode* found = constants_.FindNodeOrInsertPos(id, insert_pos)) {
CARBON_CHECK(found->constant_id.is_constant())
<< "Found non-constant in constant store for " << inst;
CARBON_CHECK(found->constant_id.is_symbolic() == is_symbolic)
<< "Mismatch in phase for constant " << inst;
return found->constant_id;
}
// Create the new inst and insert the new node.
auto inst_id =
constants_.getContext()->insts().AddInNoBlock(LocIdAndInst::NoLoc(inst));
auto constant_id = is_symbolic
? SemIR::ConstantId::ForSymbolicConstant(inst_id)
: SemIR::ConstantId::ForTemplateConstant(inst_id);
node.constant_id = constant_id;
constants_.InsertNode(new (*allocator_) ConstantNode(node), insert_pos);
// The constant value of any constant instruction is that instruction itself.
constants_.getContext()->constant_values().Set(inst_id, constant_id);
return constant_id;
}
auto ConstantStore::GetAsVector() const -> llvm::SmallVector<InstId, 0> {
llvm::SmallVector<InstId, 0> result;
result.reserve(constants_.size());
for (const ConstantNode& node : constants_) {
result.push_back(node.constant_id.inst_id());
}
// For stability, put the results into index order. This happens to also be
// insertion order.
std::sort(result.begin(), result.end(),
[](InstId a, InstId b) { return a.index < b.index; });
return result;
}
auto ConstantStore::ConstantNode::Profile(llvm::FoldingSetNodeID& id,
File* sem_ir) -> void {
ProfileConstant(id, *sem_ir, inst);
return it->second;
}
} // namespace Carbon::SemIR
+6 -17
View File
@@ -57,8 +57,8 @@ class ConstantValueStore {
// Provides storage for instructions representing deduplicated global constants.
class ConstantStore {
public:
explicit ConstantStore(File& sem_ir, llvm::BumpPtrAllocator& allocator)
: allocator_(&allocator), constants_(&sem_ir) {}
explicit ConstantStore(File& sem_ir, llvm::BumpPtrAllocator& /*allocator*/)
: sem_ir_(sem_ir) {}
// Adds a new constant instruction, or gets the existing constant with this
// value. Returns the ID of the constant.
@@ -69,25 +69,14 @@ class ConstantStore {
// Returns a copy of the constant IDs as a vector, in an arbitrary but
// stable order. This should not be used anywhere performance-sensitive.
auto GetAsVector() const -> llvm::SmallVector<InstId, 0>;
auto array_ref() const -> llvm::ArrayRef<InstId> { return constants_; }
auto size() const -> int { return constants_.size(); }
private:
// TODO: We store two copies of each constant instruction: one in insts() and
// one here. We could avoid one of those copies and store just an InstId here,
// at the cost of some more indirection when recomputing profiles during
// lookup. Once we have a representative data set, we should measure the
// impact on compile time from that change.
struct ConstantNode : llvm::FoldingSetNode {
Inst inst;
ConstantId constant_id;
auto Profile(llvm::FoldingSetNodeID& id, File* sem_ir) -> void;
};
llvm::BumpPtrAllocator* allocator_;
llvm::ContextualFoldingSet<ConstantNode, File*> constants_;
File& sem_ir_;
llvm::DenseMap<Inst, ConstantId> map_;
llvm::SmallVector<InstId, 0> constants_;
};
} // namespace Carbon::SemIR
+6
View File
@@ -43,6 +43,12 @@ class CopyOnWriteBlock {
// called once all modifications have been performed.
auto id() const -> BlockIdType { return id_; }
// Gets a canonical block ID containing the resulting elements. This assumes
// the original block ID, if specified, was also canonical.
auto GetCanonical() const -> BlockIdType {
return id_ == source_id_ ? id_ : (file_.*ValueStore)().MakeCanonical(id_);
}
// Sets the element at index `i` within the block. Lazily allocates a new
// block when the value changes for the first time.
auto Set(int i, typename BlockIdType::ElementType value) -> void {
+8 -25
View File
@@ -12,6 +12,7 @@
#include "llvm/Support/FormatVariadic.h"
#include "toolchain/base/value_store.h"
#include "toolchain/base/yaml.h"
#include "toolchain/sem_ir/bind_name.h"
#include "toolchain/sem_ir/class.h"
#include "toolchain/sem_ir/constant.h"
#include "toolchain/sem_ir/function.h"
@@ -27,22 +28,6 @@
namespace Carbon::SemIR {
struct BindNameInfo : public Printable<BindNameInfo> {
auto Print(llvm::raw_ostream& out) const -> void {
out << "{name: " << name_id << ", enclosing_scope: " << enclosing_scope_id
<< ", index: " << bind_index << "}";
}
// The name.
NameId name_id;
// The enclosing scope.
NameScopeId enclosing_scope_id;
// The index for a compile-time binding. Invalid for a runtime binding.
CompileTimeBindIndex bind_index;
};
class File;
// Provides semantic analysis on a Parse::Tree.
class File : public Printable<File> {
public:
@@ -108,16 +93,16 @@ class File : public Printable<File> {
auto identifiers() const -> const StringStoreWrapper<IdentifierId>& {
return value_stores_->identifiers();
}
auto ints() -> ValueStore<IntId>& { return value_stores_->ints(); }
auto ints() const -> const ValueStore<IntId>& {
auto ints() -> CanonicalValueStore<IntId>& { return value_stores_->ints(); }
auto ints() const -> const CanonicalValueStore<IntId>& {
return value_stores_->ints();
}
auto reals() -> ValueStore<RealId>& { return value_stores_->reals(); }
auto reals() const -> const ValueStore<RealId>& {
return value_stores_->reals();
}
auto floats() -> ValueStore<FloatId>& { return value_stores_->floats(); }
auto floats() const -> const ValueStore<FloatId>& {
auto floats() -> FloatValueStore& { return value_stores_->floats(); }
auto floats() const -> const FloatValueStore& {
return value_stores_->floats();
}
auto string_literal_values() -> StringStoreWrapper<StringLiteralValueId>& {
@@ -128,10 +113,8 @@ class File : public Printable<File> {
return value_stores_->string_literal_values();
}
auto bind_names() -> ValueStore<BindNameId>& { return bind_names_; }
auto bind_names() const -> const ValueStore<BindNameId>& {
return bind_names_;
}
auto bind_names() -> BindNameStore& { return bind_names_; }
auto bind_names() const -> const BindNameStore& { return bind_names_; }
auto functions() -> ValueStore<FunctionId>& { return functions_; }
auto functions() const -> const ValueStore<FunctionId>& { return functions_; }
auto classes() -> ValueStore<ClassId>& { return classes_; }
@@ -208,7 +191,7 @@ class File : public Printable<File> {
std::string filename_;
// Storage for bind names.
ValueStore<BindNameId> bind_names_;
BindNameStore bind_names_;
// Storage for callable objects.
ValueStore<FunctionId> functions_;
+1 -1
View File
@@ -127,7 +127,7 @@ class Formatter {
llvm::SaveAndRestore constants_scope(scope_, InstNamer::ScopeId::Constants);
out_ << inst_namer_.GetScopeName(InstNamer::ScopeId::Constants) << " ";
OpenBrace();
FormatCodeBlock(sem_ir_.constants().GetAsVector());
FormatCodeBlock(sem_ir_.constants().array_ref());
CloseBrace();
out_ << "\n\n";
}
+7
View File
@@ -203,6 +203,8 @@ struct CompileTimeBindIndex : public IndexBase,
constexpr CompileTimeBindIndex CompileTimeBindIndex::Invalid =
CompileTimeBindIndex(InvalidIndex);
// Note that InvalidIndex - 1 and InvalidIndex - 2 are used by
// DenseMapInfo<BindNameInfo>.
// The ID of a function.
struct FunctionId : public IdBase, public Printable<FunctionId> {
@@ -538,6 +540,9 @@ struct TypeBlockId : public IdBase, public Printable<TypeBlockId> {
using ElementType = TypeId;
using ValueType = llvm::MutableArrayRef<ElementType>;
// An explicitly invalid ID.
static const TypeBlockId Invalid;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "typeBlock";
@@ -545,6 +550,8 @@ struct TypeBlockId : public IdBase, public Printable<TypeBlockId> {
}
};
constexpr TypeBlockId TypeBlockId::Invalid = TypeBlockId(InvalidIndex);
// An index for element access, for structs, tuples, and classes.
struct ElementIndex : public IndexBase, public Printable<ElementIndex> {
using IndexBase::IndexBase;
+2 -2
View File
@@ -7,7 +7,7 @@
namespace Carbon::SemIR {
auto Inst::Print(llvm::raw_ostream& out) const -> void {
out << "{kind: " << kind_;
out << "{kind: " << kind();
auto print_args = [&](auto info) {
using Info = decltype(info);
@@ -19,7 +19,7 @@ auto Inst::Print(llvm::raw_ostream& out) const -> void {
}
};
switch (kind_) {
switch (kind()) {
#define CARBON_SEM_IR_INST_KIND(Name) \
case Name::Kind: \
print_args(Internal::InstLikeTypeInfo<Name>()); \
+41 -7
View File
@@ -9,6 +9,7 @@
#include <cstdint>
#include "common/check.h"
#include "common/hashing.h"
#include "common/ostream.h"
#include "common/struct_reflection.h"
#include "toolchain/base/index_base.h"
@@ -129,15 +130,17 @@ class Inst : public Printable<Inst> {
// NOLINTNEXTLINE(google-explicit-constructor)
Inst(TypedInst typed_inst)
// kind_ is always overwritten below.
: kind_(InstKind::Make({})),
: kind_(),
type_id_(TypeId::Invalid),
arg0_(InstId::InvalidIndex),
arg1_(InstId::InvalidIndex) {
if constexpr (Internal::HasKindMemberAsField<TypedInst>) {
kind_ = typed_inst.kind;
kind_ = typed_inst.kind.AsInt();
} else {
kind_ = TypedInst::Kind;
kind_ = TypedInst::Kind.AsInt();
}
CARBON_CHECK(kind_ >= 0)
<< "Negative kind values are reserved for DenseMapInfo.";
if constexpr (Internal::HasTypeIdMember<TypedInst>) {
type_id_ = typed_inst.type_id;
}
@@ -205,7 +208,9 @@ class Inst : public Printable<Inst> {
}
}
auto kind() const -> InstKind { return kind_; }
auto kind() const -> InstKind {
return InstKind::Make(static_cast<InstKind::RawEnumType>(kind_));
}
// Gets the type of the value produced by evaluating this instruction.
auto type_id() const -> TypeId { return type_id_; }
@@ -220,7 +225,9 @@ class Inst : public Printable<Inst> {
}
// Gets the kinds of IDs used for arg0 and arg1 of this instruction.
auto ArgKinds() const -> std::pair<IdKind, IdKind> { return ArgKinds(kind_); }
auto ArgKinds() const -> std::pair<IdKind, IdKind> {
return ArgKinds(kind());
}
// Gets the first argument of the instruction. InvalidIndex if there is no
// such argument.
@@ -240,12 +247,15 @@ class Inst : public Printable<Inst> {
private:
friend class InstTestHelper;
friend struct llvm::DenseMapInfo<Carbon::SemIR::Inst>;
// Table mapping instruction kinds to their argument kinds.
static const std::pair<IdKind, IdKind> ArgKindTable[];
// Raw constructor, used for testing.
// Raw constructor, used for testing and by DenseMapInfo.
explicit Inst(InstKind kind, TypeId type_id, int32_t arg0, int32_t arg1)
: Inst(kind.AsInt(), type_id, arg0, arg1) {}
explicit Inst(int32_t kind, TypeId type_id, int32_t arg0, int32_t arg1)
: kind_(kind), type_id_(type_id), arg0_(arg0), arg1_(arg1) {}
// Convert a field to its raw representation, used as `arg0_` / `arg1_`.
@@ -264,7 +274,7 @@ class Inst : public Printable<Inst> {
return BuiltinKind::FromInt(raw);
}
InstKind kind_;
int32_t kind_;
TypeId type_id_;
// Use `As` to access arg0 and arg1.
@@ -445,6 +455,30 @@ class InstBlockStore : public BlockValueStore<InstBlockId> {
}
};
// See common/hashing.h.
inline auto CarbonHashValue(const Inst& value, uint64_t seed) -> HashCode {
Hasher hasher(seed);
hasher.Hash(value);
return static_cast<HashCode>(hasher);
}
} // namespace Carbon::SemIR
template <>
struct llvm::DenseMapInfo<Carbon::SemIR::Inst> {
using Inst = Carbon::SemIR::Inst;
static auto getEmptyKey() -> Inst {
return Inst(-1, Carbon::SemIR::TypeId::Invalid, 0, 0);
}
static auto getTombstoneKey() -> Inst {
return Inst(-2, Carbon::SemIR::TypeId::Invalid, 0, 0);
}
static auto getHashValue(const Inst& val) -> unsigned {
return static_cast<uint64_t>(Carbon::HashValue(val));
}
static auto isEqual(const Inst& lhs, const Inst& rhs) -> bool {
return std::memcmp(&lhs, &rhs, sizeof(Inst)) == 0;
}
};
#endif // CARBON_TOOLCHAIN_SEM_IR_INST_H_
+1 -1
View File
@@ -27,7 +27,7 @@ InstNamer::InstNamer(const Lex::TokenizedBuffer& tokenized_buffer,
scopes.resize(static_cast<size_t>(GetScopeFor(NumberOfScopesTag())));
// Build the constants scope.
CollectNamesInBlock(ScopeId::Constants, sem_ir.constants().GetAsVector());
CollectNamesInBlock(ScopeId::Constants, sem_ir.constants().array_ref());
// Build the file scope.
CollectNamesInBlock(ScopeId::File, sem_ir.top_inst_block_id());
-123
View File
@@ -1,123 +0,0 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/sem_ir/inst_profile.h"
#include "toolchain/sem_ir/file.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/inst.h"
namespace Carbon::SemIR {
// A function to profile an argument of an instruction.
using ProfileArgFunction = auto(llvm::FoldingSetNodeID&, const File& sem_ir,
int32_t arg) -> void;
// Profiling for unused arguments.
static auto NullProfileArgFunction(llvm::FoldingSetNodeID& /*id*/,
const File& /*sem_ir*/, int32_t arg)
-> void {
CARBON_CHECK(arg == IdBase::InvalidIndex)
<< "Unexpected value for unused argument.";
}
// Profiling for ID arguments that should participate in the instruction's
// value.
static auto DefaultProfileArgFunction(llvm::FoldingSetNodeID& id,
const File& /*sem_ir*/, int32_t arg)
-> void {
id.AddInteger(arg);
}
// Profiling for block ID arguments for which the content of the block should be
// included.
static auto InstBlockProfileArgFunction(llvm::FoldingSetNodeID& id,
const File& sem_ir, int32_t arg)
-> void {
auto inst_block_id = InstBlockId(arg);
if (!inst_block_id.is_valid()) {
id.AddInteger(-1);
return;
}
auto inst_block = sem_ir.inst_blocks().Get(inst_block_id);
id.AddInteger(inst_block.size());
for (auto inst_id : inst_block) {
id.AddInteger(inst_id.index);
}
}
// Profiling for type block ID arguments for which the content of the block
// should be included.
static auto TypeBlockProfileArgFunction(llvm::FoldingSetNodeID& id,
const File& sem_ir, int32_t arg)
-> void {
auto type_block_id = TypeBlockId(arg);
if (!type_block_id.is_valid()) {
id.AddInteger(-1);
return;
}
auto type_block = sem_ir.type_blocks().Get(type_block_id);
id.AddInteger(type_block.size());
for (auto type_id : type_block) {
id.AddInteger(type_id.index);
}
}
// Profiling for integer IDs.
static auto IntProfileArgFunction(llvm::FoldingSetNodeID& id,
const File& sem_ir, int32_t arg) -> void {
sem_ir.ints().Get(IntId(arg)).Profile(id);
}
// Profiling for real number IDs.
static auto RealProfileArgFunction(llvm::FoldingSetNodeID& id,
const File& sem_ir, int32_t arg) -> void {
const auto& real = sem_ir.reals().Get(RealId(arg));
// TODO: Profile the value rather than the syntactic form.
real.mantissa.Profile(id);
real.exponent.Profile(id);
id.AddBoolean(real.is_decimal);
}
// Profiling for BindNameInfo.
static auto BindNameIdProfileArgFunction(llvm::FoldingSetNodeID& id,
const File& sem_ir, int32_t arg)
-> void {
const auto& [name_id, enclosing_scope_id, bind_index] =
sem_ir.bind_names().Get(BindNameId(arg));
id.AddInteger(name_id.index);
id.AddInteger(enclosing_scope_id.index);
id.AddInteger(bind_index.index);
}
// Profiles the given instruction argument, which is of the specified kind.
static auto ProfileArg(llvm::FoldingSetNodeID& id, const File& sem_ir,
IdKind arg_kind, int32_t arg) -> void {
static constexpr std::array<ProfileArgFunction*, IdKind::NumValues>
ProfileFunctions = [] {
std::array<ProfileArgFunction*, IdKind::NumValues> array;
array.fill(DefaultProfileArgFunction);
array[IdKind::None.ToIndex()] = NullProfileArgFunction;
array[IdKind::For<InstBlockId>.ToIndex()] = InstBlockProfileArgFunction;
array[IdKind::For<TypeBlockId>.ToIndex()] = TypeBlockProfileArgFunction;
array[IdKind::For<IntId>.ToIndex()] = IntProfileArgFunction;
array[IdKind::For<RealId>.ToIndex()] = RealProfileArgFunction;
array[IdKind::For<BindNameId>.ToIndex()] = BindNameIdProfileArgFunction;
return array;
}();
ProfileFunctions[arg_kind.ToIndex()](id, sem_ir, arg);
}
auto ProfileConstant(llvm::FoldingSetNodeID& id, const File& sem_ir, Inst inst)
-> void {
inst.kind().Profile(id);
id.AddInteger(inst.type_id().index);
auto arg_kinds = inst.ArgKinds();
ProfileArg(id, sem_ir, arg_kinds.first, inst.arg0());
ProfileArg(id, sem_ir, arg_kinds.second, inst.arg1());
}
} // namespace Carbon::SemIR
-21
View File
@@ -1,21 +0,0 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CARBON_TOOLCHAIN_SEM_IR_INST_PROFILE_H_
#define CARBON_TOOLCHAIN_SEM_IR_INST_PROFILE_H_
#include "llvm/ADT/FoldingSet.h"
#include "toolchain/sem_ir/file.h"
#include "toolchain/sem_ir/inst.h"
namespace Carbon::SemIR {
// Computes a profile of the given constant instruction, for canonicalization /
// deduplication.
auto ProfileConstant(llvm::FoldingSetNodeID& id, const File& sem_ir, Inst inst)
-> void;
} // namespace Carbon::SemIR
#endif // CARBON_TOOLCHAIN_SEM_IR_INST_PROFILE_H_
-2
View File
@@ -5,8 +5,6 @@
#include "toolchain/sem_ir/name.h"
#include "llvm/ADT/StringSwitch.h"
#include "toolchain/sem_ir/file.h"
#include "toolchain/sem_ir/inst_profile.h"
namespace Carbon::SemIR {