{{- /* -------------------------------------------------------------------------------- Template file for use with tools/intrinsic-gen to generate intrinsic_table.inl Used by IntrinsicTable.cc for intrinsic overload resolution. See: * tools/cmd/intrinsic-gen/gen for structures used by this template * https://golang.org/pkg/text/template/ for documentation on the template syntax -------------------------------------------------------------------------------- */ -}} // clang-format off /// ParameterInfo describes a parameter struct ParameterInfo { /// The parameter usage (parameter name in definition file) ParameterUsage const usage; /// Pointer to a list of indices that are used to match the parameter type. /// The matcher indices index on Matchers::type and / or Matchers::number. /// These indices are consumed by the matchers themselves. /// The first index is always a TypeMatcher. MatcherIndex const* const matcher_indices; }; /// OpenTypeInfo describes an open type struct OpenTypeInfo { /// Name of the open type (e.g. 'T') const char* name; /// Optional type matcher constraint. /// Either an index in Matchers::type, or kNoMatcher MatcherIndex const matcher_index; }; /// OpenNumberInfo describes an open number struct OpenNumberInfo { /// Name of the open number (e.g. 'N') const char* name; /// Optional number matcher constraint. /// Either an index in Matchers::number, or kNoMatcher MatcherIndex const matcher_index; }; /// OverloadInfo describes a single function overload struct OverloadInfo { /// Total number of parameters for the overload uint8_t const num_parameters; /// Total number of open types for the overload uint8_t const num_open_types; /// Total number of open numbers for the overload uint8_t const num_open_numbers; /// Pointer to the first open type OpenTypeInfo const* const open_types; /// Pointer to the first open number OpenNumberInfo const* const open_numbers; /// Pointer to the first parameter ParameterInfo const* const parameters; /// Pointer to a list of matcher indices that index on Matchers::type and /// Matchers::number, used to build the return type. If the function has no /// return type then this is null. MatcherIndex const* const return_matcher_indices; }; /// IntrinsicInfo describes an intrinsic function struct IntrinsicInfo { /// Number of overloads of the intrinsic function uint8_t const num_overloads; /// Pointer to the start of the overloads for the function OverloadInfo const* const overloads; }; {{ with .Sem -}} {{ range .Types -}} {{ template "Type" . }} {{ end -}} {{ range .TypeMatchers -}} {{ template "TypeMatcher" . }} {{ end -}} {{ range .EnumMatchers -}} {{ template "EnumMatcher" . }} {{ end -}} {{- end -}} {{- with IntrinsicTable -}} {{- template "Matchers" . }} constexpr MatcherIndex kMatcherIndices[] = { {{- range $i, $idx := .MatcherIndices }} /* [{{$i}}] */ {{$idx}}, {{- end }} }; // Assert that the MatcherIndex is big enough to index all the matchers, plus // kNoMatcher. static_assert(static_cast(sizeof(kMatcherIndices) / sizeof(kMatcherIndices[0])) < static_cast(std::numeric_limits::max() - 1), "MatcherIndex is not large enough to index kMatcherIndices"); constexpr ParameterInfo kParameters[] = { {{- range $i, $p := .Parameters }} { /* [{{$i}}] */ /* usage */ ParameterUsage:: {{- if $p.Usage }}k{{PascalCase $p.Usage}} {{- else }}kNone {{- end }}, /* matcher indices */ &kMatcherIndices[{{$p.MatcherIndicesOffset}}], }, {{- end }} }; constexpr OpenTypeInfo kOpenTypes[] = { {{- range $i, $o := .OpenTypes }} { /* [{{$i}}] */ /* name */ "{{$o.Name}}", /* matcher index */ {{- if ge $o.MatcherIndex 0 }} {{$o.MatcherIndex}} {{- else }} kNoMatcher {{- end }}, }, {{- end }} }; constexpr OpenNumberInfo kOpenNumbers[] = { {{- range $i, $o := .OpenNumbers }} { /* [{{$i}}] */ /* name */ "{{$o.Name}}", /* matcher index */ {{- if ge $o.MatcherIndex 0 }} {{$o.MatcherIndex}} {{- else }} kNoMatcher {{- end }}, }, {{- end }} }; constexpr OverloadInfo kOverloads[] = { {{- range $i, $o := .Overloads }} { /* [{{$i}}] */ /* num parameters */ {{$o.NumParameters}}, /* num open types */ {{$o.NumOpenTypes}}, /* num open numbers */ {{$o.NumOpenNumbers}}, /* open types */ {{- if $o.OpenTypesOffset }} &kOpenTypes[{{$o.OpenTypesOffset}}], {{- else }} nullptr, {{- end }} /* open numbers */ {{- if $o.OpenNumbersOffset }} &kOpenNumbers[{{$o.OpenNumbersOffset}}] {{- else }} nullptr {{- end }}, /* parameters */ &kParameters[{{$o.ParametersOffset}}], /* return matcher indices */ {{- if $o.ReturnMatcherIndicesOffset }} &kMatcherIndices[{{$o.ReturnMatcherIndicesOffset}}] {{- else }} nullptr {{- end }}, }, {{- end }} }; constexpr IntrinsicInfo kIntrinsics[] = { {{- range $i, $f := .Functions }} { /* [{{$i}}] */ {{- range $f.OverloadDescriptions }} /* {{.}} */ {{- end }} /* num overloads */ {{$f.NumOverloads}}, /* overloads */ &kOverloads[{{$f.OverloadsOffset}}], }, {{- end }} }; // clang-format on {{ end -}} {{- /* ------------------------------------------------------------------ */ -}} {{- define "Type" -}} {{- /* ------------------------------------------------------------------ */ -}} {{- $class := PascalCase .Name -}} /// TypeMatcher for 'type {{.Name}}' {{- if .Decl.Source.S.Filepath }} /// @see {{.Decl.Source}} {{- end }} class {{$class}} : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. /// Match may close open types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr const sem::Type* Match(MatchState& state, const sem::Type* type) const override; /// @param state the MatchState /// @return a string representation of the matcher. std::string String(MatchState& state) const override; }; const sem::Type* {{$class}}::Match(MatchState& state, const sem::Type* ty) const { {{- range .TemplateParams }} {{- template "DeclareLocalTemplateParam" . }} {{- end }} if (!match_{{.Name}}(ty{{range .TemplateParams}}, {{.GetName}}{{end}})) { return nullptr; } {{- range .TemplateParams }} {{.Name}} = {{ template "MatchTemplateParam" .}}({{.Name}}); if ({{ template "IsTemplateParamInvalid" .}}) { return nullptr; } {{- end }} return build_{{.Name}}(state{{range .TemplateParams}}, {{.GetName}}{{end}}); } std::string {{$class}}::String(MatchState&{{if .TemplateParams}} state{{end}}) const { {{- range .TemplateParams }} {{- template "DeclareLocalTemplateParamName" . }} {{- end }} {{- if .DisplayName }} std::stringstream ss; ss{{range SplitDisplayName .DisplayName}} << {{.}}{{end}}; return ss.str(); {{- else if .TemplateParams }} return "{{.Name}}<"{{template "AppendTemplateParamNames" .TemplateParams}} + ">"; {{- else }} return "{{.Name}}"; {{- end }} } {{ end -}} {{- /* ------------------------------------------------------------------ */ -}} {{- define "TypeMatcher" -}} {{- /* ------------------------------------------------------------------ */ -}} {{- $class := PascalCase .Name -}} /// TypeMatcher for 'match {{.Name}}' {{- if .Decl.Source.S.Filepath }} /// @see {{.Decl.Source}} {{- end }} class {{$class}} : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. /// Match may close open types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr const sem::Type* Match(MatchState& state, const sem::Type* type) const override; /// @param state the MatchState /// @return a string representation of the matcher. std::string String(MatchState& state) const override; }; const sem::Type* {{$class}}::Match(MatchState& state, const sem::Type* ty) const { {{- range .Types }} if (match_{{.Name}}(ty)) { return build_{{.Name}}(state); } {{- end }} return nullptr; } std::string {{$class}}::String(MatchState&) const { return " {{- range .Types -}} {{- if IsFirstIn . $.Types }}{{.Name}} {{- else if IsLastIn . $.Types }} or {{.Name}} {{- else }}, {{.Name}} {{- end -}} {{- end -}} "; } {{ end -}} {{- /* ------------------------------------------------------------------ */ -}} {{- define "EnumMatcher" -}} {{- /* ------------------------------------------------------------------ */ -}} {{- $class := PascalCase .Name -}} {{- $enum := PascalCase .Enum.Name -}} /// EnumMatcher for 'match {{.Name}}' {{- if .Decl.Source.S.Filepath }} /// @see {{.Decl.Source}} {{- end }} class {{$class}} : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. /// Match may close open types and numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set Number Match(MatchState& state, Number number) const override; /// @param state the MatchState /// @return a string representation of the matcher. std::string String(MatchState& state) const override; }; {{ if eq 1 (len .Options) -}} {{- $option := index .Options 0 }} {{- $entry := printf "k%v" (PascalCase $option.Name) -}} Number {{$class}}::Match(MatchState&, Number number) const { if (number.IsAny() || number.Value() == static_cast({{$enum}}::{{$entry}})) { return Number({{$enum}}::{{$entry}}); } return Number::invalid; } {{- else -}} Number {{$class}}::Match(MatchState&, Number number) const { switch (static_cast<{{$enum}}>(number.Value())) { {{- range .Options }} case {{$enum}}::k{{PascalCase .Name}}: {{- end }} return number; default: return Number::invalid; } } {{- end }} std::string {{$class}}::String(MatchState&) const { return " {{- range .Options -}} {{- if IsFirstIn . $.Options }}{{.Name}} {{- else if IsLastIn . $.Options }} or {{.Name}} {{- else }}, {{.Name}} {{- end -}} {{- end -}} "; } {{ end -}} {{- /* ------------------------------------------------------------------ */ -}} {{- define "Matchers" -}} {{- /* ------------------------------------------------------------------ */ -}} /// Matchers holds type and number matchers class Matchers { private: {{- $t_names := Map -}} {{- $n_names := Map -}} {{- range Iterate .Sem.MaxOpenTypes -}} {{- $name := printf "open_type_%v" . -}} {{- $t_names.Put . $name }} OpenTypeMatcher {{$name}}_{ {{- . -}} }; {{- end }} {{- range Iterate .Sem.MaxOpenNumbers -}} {{- $name := printf "open_number_%v" . -}} {{- $n_names.Put . $name }} OpenNumberMatcher {{$name}}_{ {{- . -}} }; {{- end }} {{- range .Sem.Types -}} {{- $name := PascalCase .Name -}} {{- $t_names.Put . $name }} {{$name}} {{$name}}_; {{- end }} {{- range .Sem.TypeMatchers -}} {{- $name := PascalCase .Name -}} {{- $t_names.Put . $name }} {{$name}} {{$name}}_; {{- end }} {{- range .Sem.EnumMatchers -}} {{- $name := PascalCase .Name -}} {{- $n_names.Put . $name }} {{$name}} {{$name}}_; {{- end }} public: /// Constructor Matchers(); /// Destructor ~Matchers(); /// The open-types, types, and type matchers TypeMatcher const* const type[{{len .TMatchers}}] = { {{- range $i, $m := .TMatchers }} /* [{{$i}}] */ {{- if $m }} &{{$t_names.Get $m}}_, {{- else }} &{{$t_names.Get $i}}_, {{- end }} {{- end }} }; /// The open-numbers, and number matchers NumberMatcher const* const number[{{len .NMatchers}}] = { {{- range $i, $m := .NMatchers }} /* [{{$i}}] */ {{- if $m }} &{{$n_names.Get $m}}_, {{- else }} &{{$n_names.Get $i}}_, {{- end }} {{- end }} }; }; Matchers::Matchers() = default; Matchers::~Matchers() = default; {{- end -}} {{- /* ------------------------------------------------------------------ */ -}} {{- define "DeclareLocalTemplateParam" -}} {{- /* ------------------------------------------------------------------ */ -}} {{- if IsTemplateTypeParam . }} const sem::Type* {{.Name}} = nullptr; {{- else if IsTemplateNumberParam . }} Number {{.Name}} = Number::invalid; {{- else if IsTemplateEnumParam . }} Number {{.Name}} = Number::invalid; {{- end -}} {{- end -}} {{- /* ------------------------------------------------------------------ */ -}} {{- define "DeclareLocalTemplateParamName" -}} {{- /* ------------------------------------------------------------------ */ -}} {{- if IsTemplateTypeParam . }} const std::string {{.Name}} = state.TypeName(); {{- else if IsTemplateNumberParam . }} const std::string {{.Name}} = state.NumName(); {{- else if IsTemplateEnumParam . }} const std::string {{.Name}} = state.NumName(); {{- end -}} {{- end -}} {{- /* ------------------------------------------------------------------ */ -}} {{- define "MatchTemplateParam" -}} {{- /* ------------------------------------------------------------------ */ -}} {{- if IsTemplateTypeParam . -}} state.Type {{- else if IsTemplateNumberParam . -}} state.Num {{- else if IsTemplateEnumParam . -}} state.Num {{- end -}} {{- end -}} {{- /* ------------------------------------------------------------------ */ -}} {{- define "IsTemplateParamInvalid" -}} {{- /* ------------------------------------------------------------------ */ -}} {{- if IsTemplateTypeParam . -}} {{.Name}} == nullptr {{- else if IsTemplateNumberParam . -}} !{{.Name}}.IsValid() {{- else if IsTemplateEnumParam . -}} !{{.Name}}.IsValid() {{- end -}} {{- end -}} {{- /* ------------------------------------------------------------------ */ -}} {{- define "AppendTemplateParamNames" -}} {{- /* ------------------------------------------------------------------ */ -}} {{- range $i, $ := . -}} {{- if $i }} + ", " + {{.Name}} {{- else }} + {{.Name}} {{- end -}} {{- end -}} {{- end -}}