Skip to content

Commit 8ede14d

Browse files
authored
use static std::array for grammar tables again (KhronosGroup#6132)
This avoids the C++ global initializers by making the constructors for OperandDesc and InstructionDesc constexpr. In turn, the std::array static variables over those types can be initialized at compile time, not at runtime. This also avoids the implied mutex inside the function bodies.
1 parent 54f2f3d commit 8ede14d

File tree

3 files changed

+31
-46
lines changed

3 files changed

+31
-46
lines changed

source/table2.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,12 @@ utils::Span<const spvtools::Extension> InstructionDesc::extensions() const {
139139
spv_result_t LookupOpcode(spv::Op opcode, const InstructionDesc** desc) {
140140
// Metaphor: Look for the needle in the haystack.
141141
const InstructionDesc needle(opcode);
142-
const auto& descs = getInstructionDesc();
143142
auto where = std::lower_bound(
144-
descs.begin(), descs.end(), needle,
143+
kInstructionDesc.begin(), kInstructionDesc.end(), needle,
145144
[&](const InstructionDesc& lhs, const InstructionDesc& rhs) {
146145
return uint32_t(lhs.opcode) < uint32_t(rhs.opcode);
147146
});
148-
if (where != descs.end() && where->opcode == opcode) {
147+
if (where != kInstructionDesc.end() && where->opcode == opcode) {
149148
*desc = &*where;
150149
return SPV_SUCCESS;
151150
}
@@ -163,9 +162,10 @@ spv_result_t LookupOpcode(const char* name, const InstructionDesc** desc) {
163162
return std::strcmp(lhs_chars, rhs_chars) < 0;
164163
};
165164

166-
const auto& names = getInstructionNames();
167-
auto where = std::lower_bound(names.begin(), names.end(), needle, less);
168-
if (where != names.end() && std::strcmp(getChars(where->name), name) == 0) {
165+
auto where = std::lower_bound(kInstructionNames.begin(),
166+
kInstructionNames.end(), needle, less);
167+
if (where != kInstructionNames.end() &&
168+
std::strcmp(getChars(where->name), name) == 0) {
169169
return LookupOpcode(static_cast<spv::Op>(where->value), desc);
170170
}
171171
return SPV_ERROR_INVALID_LOOKUP;
@@ -209,7 +209,7 @@ spv_result_t LookupOperand(spv_operand_type_t type, uint32_t value,
209209
return SPV_ERROR_INVALID_LOOKUP;
210210
}
211211

212-
auto span = ir.apply(getOperandsByValue().data());
212+
auto span = ir.apply(kOperandsByValue.data());
213213

214214
// Metaphor: Look for the needle in the haystack.
215215
// The operand value is the first member.
@@ -233,7 +233,7 @@ spv_result_t LookupOperand(spv_operand_type_t type, const char* name,
233233
return SPV_ERROR_INVALID_LOOKUP;
234234
}
235235

236-
auto span = ir.apply(getOperandNames().data());
236+
auto span = ir.apply(kOperandNames.data());
237237

238238
// The comparison function knows to use (name, name_len) as the
239239
// string to compare against when the value is kSentinel.
@@ -278,10 +278,9 @@ bool GetExtensionFromString(const char* name, Extension* extension) {
278278
return std::strcmp(lhs_chars, rhs_chars) < 0;
279279
};
280280

281-
const auto& extension_names = getExtensionNames();
282-
auto where = std::lower_bound(extension_names.begin(), extension_names.end(),
281+
auto where = std::lower_bound(kExtensionNames.begin(), kExtensionNames.end(),
283282
needle, less);
284-
if (where != extension_names.end() &&
283+
if (where != kExtensionNames.end() &&
285284
std::strcmp(getChars(where->name), name) == 0) {
286285
*extension = static_cast<Extension>(where->value);
287286
return true;

source/table2.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ struct OperandDesc {
110110
utils::Span<const spv::Capability> capabilities() const;
111111
utils::Span<const spvtools::Extension> extensions() const;
112112

113-
OperandDesc(uint32_t v, IndexRange o, IndexRange n, IndexRange a,
114-
IndexRange c, IndexRange e, uint32_t mv, uint32_t lv)
113+
constexpr OperandDesc(uint32_t v, IndexRange o, IndexRange n, IndexRange a,
114+
IndexRange c, IndexRange e, uint32_t mv, uint32_t lv)
115115
: value(v),
116116
operands_range(o),
117117
name_range(n),
@@ -121,7 +121,7 @@ struct OperandDesc {
121121
minVersion(mv),
122122
lastVersion(lv) {}
123123

124-
OperandDesc(uint32_t v) : value(v) {}
124+
constexpr OperandDesc(uint32_t v) : value(v) {}
125125

126126
OperandDesc(const OperandDesc&) = delete;
127127
OperandDesc(OperandDesc&&) = delete;
@@ -158,9 +158,10 @@ struct InstructionDesc {
158158
utils::Span<const spv::Capability> capabilities() const;
159159
utils::Span<const spvtools::Extension> extensions() const;
160160

161-
InstructionDesc(spv::Op oc, bool hr, bool ht, IndexRange o, IndexRange n,
162-
IndexRange a, IndexRange c, IndexRange e, uint32_t mv,
163-
uint32_t lv, PrintingClass pc)
161+
constexpr InstructionDesc(spv::Op oc, bool hr, bool ht, IndexRange o,
162+
IndexRange n, IndexRange a, IndexRange c,
163+
IndexRange e, uint32_t mv, uint32_t lv,
164+
PrintingClass pc)
164165
: opcode(oc),
165166
hasResult(hr),
166167
hasType(ht),
@@ -173,7 +174,7 @@ struct InstructionDesc {
173174
lastVersion(lv),
174175
printingClass(pc) {}
175176

176-
InstructionDesc(spv::Op oc) : opcode(oc) {}
177+
constexpr InstructionDesc(spv::Op oc) : opcode(oc) {}
177178

178179
InstructionDesc(const InstructionDesc&) = delete;
179180
InstructionDesc(InstructionDesc&&) = delete;

utils/ggt.py

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -246,13 +246,10 @@ def ComputeExtensionDecls(self) -> None:
246246
// The fields in order are:
247247
// name, indexing into kStrings
248248
// enum value""")
249-
parts.append("const std::array<NameValue,{}>& getExtensionNames() {{".format(len(self.extensions)))
250-
parts.append(" static const std::array<NameValue,{}> kExtensionNames{{{{".format(len(self.extensions)))
249+
parts.append("static const std::array<NameValue,{}> kExtensionNames{{{{".format(len(self.extensions)))
251250
for e in self.extensions:
252251
parts.append(' {{{}, static_cast<uint32_t>({})}},'.format(self.context.AddString(e), to_safe_identifier(e)))
253-
parts.append(" }};")
254-
parts.append(" return kExtensionNames;")
255-
parts.append("}\n")
252+
parts.append("}};\n")
256253
self.body_decls.extend(parts)
257254

258255
def ComputeOperandTables(self) -> None:
@@ -358,12 +355,9 @@ def ShouldEmit(operand_kind_json: Dict[str,any]):
358355
// The fields in order are:
359356
// name, either the primary name or an alias, indexing into kStrings
360357
// enum value""")
361-
parts.append("const std::array<NameValue, {}>& getOperandNames() {{".format(len(operand_name_strings)))
362-
parts.append(" static const std::array<NameValue, {}> kOperandNames{{{{".format(len(operand_name_strings)))
363-
parts.extend([' ' + str(x) for x in operand_name_strings])
364-
parts.append(" }};")
365-
parts.append(" return kOperandNames;")
366-
parts.append("}\n")
358+
parts.append("static const std::array<NameValue, {}> kOperandNames{{{{".format(len(operand_name_strings)))
359+
parts.extend([' ' + str(x) for x in operand_name_strings])
360+
parts.append("}};\n")
367361
self.body_decls.extend(parts)
368362

369363
parts.append("""// Maps an operand kind to possible names for operands of that kind.
@@ -421,12 +415,9 @@ def ShouldEmit(operand_kind_json: Dict[str,any]):
421415
// extensions, as an IndexRange into kExtensionSpans
422416
// version, first version of SPIR-V that has it
423417
// lastVersion, last version of SPIR-V that has it""")
424-
parts.append("const std::array<OperandDesc, {}>& getOperandsByValue() {{".format(len(operands_by_value)))
425-
parts.append(" static const std::array<OperandDesc, {}> kOperandsByValue{{{{".format(len(operands_by_value)))
426-
parts.extend([' ' + str(x) for x in operands_by_value])
427-
parts.append(" }};\n")
428-
parts.append(" return kOperandsByValue;\n")
429-
parts.append("}\n")
418+
parts.append("static const std::array<OperandDesc, {}> kOperandsByValue{{{{".format(len(operands_by_value)))
419+
parts.extend([' ' + str(x) for x in operands_by_value])
420+
parts.append("}};\n")
430421
self.body_decls.extend(parts)
431422

432423
parts = []
@@ -507,12 +498,9 @@ def ComputeInstructionTables(self, insts) -> None:
507498
// The fields in order are:
508499
// name, either the primary name or an alias, indexing into kStrings
509500
// opcode value""")
510-
parts.append("const std::array<NameValue, {}>& getInstructionNames() {{".format(len(inst_name_strings)))
511-
parts.append(" static const std::array<NameValue, {}> kInstructionNames{{{{".format(len(inst_name_strings)))
512-
parts.extend([' ' + str(x) for x in inst_name_strings])
513-
parts.append(" }};\n")
514-
parts.append(" return kInstructionNames;\n")
515-
parts.append("}\n")
501+
parts.append("static const std::array<NameValue, {}> kInstructionNames{{{{".format(len(inst_name_strings)))
502+
parts.extend([' ' + str(x) for x in inst_name_strings])
503+
parts.append("}};\n")
516504
self.body_decls.extend(parts)
517505

518506
# Create the array of InstructionDesc
@@ -565,12 +553,9 @@ def ComputeInstructionTables(self, insts) -> None:
565553
// extensions, as an IndexRange into kExtensionSpans
566554
// version, first version of SPIR-V that has it
567555
// lastVersion, last version of SPIR-V that has it""")
568-
parts.append("const std::array<InstructionDesc, {}>& getInstructionDesc() {{".format(len(lines)));
569-
parts.append(" static const std::array<InstructionDesc, {}> kInstructionDesc{{{{".format(len(lines)));
556+
parts.append("static const std::array<InstructionDesc, {}> kInstructionDesc{{{{".format(len(lines)));
570557
parts.extend([' ' + l for l in lines])
571-
parts.append(" }};\n");
572-
parts.append(" return kInstructionDesc;");
573-
parts.append("}\n");
558+
parts.append("}};\n");
574559
self.body_decls.extend(parts)
575560

576561

0 commit comments

Comments
 (0)