Skip to content

[utils][TableGen] Treat clause aliases equally with names #141763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions llvm/include/llvm/Frontend/Directive/DirectiveBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,23 @@ class DirectiveLanguage {
string flangClauseBaseClass = "";
}

// Information about values accepted by enum-like clauses
class ClauseVal<string n, int v, bit uv> {
// Name of the clause value.
// Some clauses take an argument from a predefined list of allowed keyword
// values. For example, assume a clause "someclause" with an argument from
// the list "foo", "bar", "baz". In the user source code this would look
// like "someclause(foo)", whereas in the compiler the values would be
// represented as
// enum someclause.enumClauseValue {
// Xyz_foo = v_foo,
// Xyz_bar = v_bar,
// Xyz_baz = v_baz,
// }
// The "Xyz_..." are the _record_ names of EnumVal's:
// def Xyz_foo = EnumVal<"foo", v_foo>;
// def Xyz_bar = EnumVal<"bar", v_bar>;
// def Xyz_baz = EnumVal<"baz", v_baz>;
//
class EnumVal<string n, int v, bit uv> {
// Spelling of the value.
string name = n;

// Integer value of the clause.
Expand Down Expand Up @@ -90,7 +104,7 @@ class Clause<string c> {
string enumClauseValue = "";

// List of allowed clause values
list<ClauseVal> allowedClauseValues = [];
list<EnumVal> allowedClauseValues = [];

// If set to true, value class is part of a list. Single class by default.
bit isValueList = false;
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/Frontend/OpenACC/ACC.td
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ def ACCC_Create : Clause<"create"> {
}

// 2.5.16
def ACC_Default_none : ClauseVal<"none", 1, 1> { let isDefault = 1; }
def ACC_Default_present : ClauseVal<"present", 0, 1> {}
def ACC_Default_none : EnumVal<"none", 1, 1> { let isDefault = 1; }
def ACC_Default_present : EnumVal<"present", 0, 1> {}

def ACCC_Default : Clause<"default"> {
let flangClass = "AccDefaultClause";
Expand Down
64 changes: 32 additions & 32 deletions llvm/include/llvm/Frontend/OpenMP/OMP.td
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ def OMPC_AtomicDefaultMemOrder : Clause<"atomic_default_mem_order"> {
let flangClass = "OmpAtomicDefaultMemOrderClause";
}

def OMP_BIND_parallel : ClauseVal<"parallel",1,1> {}
def OMP_BIND_teams : ClauseVal<"teams",2,1> {}
def OMP_BIND_thread : ClauseVal<"thread",3,1> { let isDefault = true; }
def OMP_BIND_parallel : EnumVal<"parallel",1,1> {}
def OMP_BIND_teams : EnumVal<"teams",2,1> {}
def OMP_BIND_thread : EnumVal<"thread",3,1> { let isDefault = true; }
def OMPC_Bind : Clause<"bind"> {
let clangClass = "OMPBindClause";
let flangClass = "OmpBindClause";
Expand All @@ -91,11 +91,11 @@ def OMPC_Bind : Clause<"bind"> {
];
}

def OMP_CANCELLATION_CONSTRUCT_Parallel : ClauseVal<"parallel", 1, 1> {}
def OMP_CANCELLATION_CONSTRUCT_Loop : ClauseVal<"loop", 2, 1> {}
def OMP_CANCELLATION_CONSTRUCT_Sections : ClauseVal<"sections", 3, 1> {}
def OMP_CANCELLATION_CONSTRUCT_Taskgroup : ClauseVal<"taskgroup", 4, 1> {}
def OMP_CANCELLATION_CONSTRUCT_None : ClauseVal<"none", 5, 0> {
def OMP_CANCELLATION_CONSTRUCT_Parallel : EnumVal<"parallel", 1, 1> {}
def OMP_CANCELLATION_CONSTRUCT_Loop : EnumVal<"loop", 2, 1> {}
def OMP_CANCELLATION_CONSTRUCT_Sections : EnumVal<"sections", 3, 1> {}
def OMP_CANCELLATION_CONSTRUCT_Taskgroup : EnumVal<"taskgroup", 4, 1> {}
def OMP_CANCELLATION_CONSTRUCT_None : EnumVal<"none", 5, 0> {
let isDefault = 1;
}
def OMPC_CancellationConstructType : Clause<"cancellation_construct_type"> {
Expand Down Expand Up @@ -210,8 +210,8 @@ def OMPC_From : Clause<"from"> {
def OMPC_Full: Clause<"full"> {
let clangClass = "OMPFullClause";
}
def OMP_GRAINSIZE_Strict : ClauseVal<"strict", 1, 1> {}
def OMP_GRAINSIZE_Unknown : ClauseVal<"unknown", 2, 0> { let isDefault = 1; }
def OMP_GRAINSIZE_Strict : EnumVal<"strict", 1, 1> {}
def OMP_GRAINSIZE_Unknown : EnumVal<"unknown", 2, 0> { let isDefault = 1; }
def OMPC_GrainSize : Clause<"grainsize"> {
let clangClass = "OMPGrainsizeClause";
let flangClass = "OmpGrainsizeClause";
Expand Down Expand Up @@ -278,12 +278,12 @@ def OMPC_Map : Clause<"map"> {
def OMPC_Match : Clause<"match"> {
let flangClass = "OmpMatchClause";
}
def OMP_MEMORY_ORDER_SeqCst : ClauseVal<"seq_cst", 1, 1> {}
def OMP_MEMORY_ORDER_AcqRel : ClauseVal<"acq_rel", 2, 1> {}
def OMP_MEMORY_ORDER_Acquire : ClauseVal<"acquire", 3, 1> {}
def OMP_MEMORY_ORDER_Release : ClauseVal<"release", 4, 1> {}
def OMP_MEMORY_ORDER_Relaxed : ClauseVal<"relaxed", 5, 1> {}
def OMP_MEMORY_ORDER_Default : ClauseVal<"default", 6, 0> {
def OMP_MEMORY_ORDER_SeqCst : EnumVal<"seq_cst", 1, 1> {}
def OMP_MEMORY_ORDER_AcqRel : EnumVal<"acq_rel", 2, 1> {}
def OMP_MEMORY_ORDER_Acquire : EnumVal<"acquire", 3, 1> {}
def OMP_MEMORY_ORDER_Release : EnumVal<"release", 4, 1> {}
def OMP_MEMORY_ORDER_Relaxed : EnumVal<"relaxed", 5, 1> {}
def OMP_MEMORY_ORDER_Default : EnumVal<"default", 6, 0> {
let isDefault = 1;
}
def OMPC_MemoryOrder : Clause<"memory_order"> {
Expand Down Expand Up @@ -337,8 +337,8 @@ def OMPC_Novariants : Clause<"novariants"> {
def OMPC_NoWait : Clause<"nowait"> {
let clangClass = "OMPNowaitClause";
}
def OMP_NUMTASKS_Strict : ClauseVal<"strict", 1, 1> {}
def OMP_NUMTASKS_Unknown : ClauseVal<"unknown", 2, 0> { let isDefault = 1; }
def OMP_NUMTASKS_Strict : EnumVal<"strict", 1, 1> {}
def OMP_NUMTASKS_Unknown : EnumVal<"unknown", 2, 0> { let isDefault = 1; }
def OMPC_NumTasks : Clause<"num_tasks"> {
let clangClass = "OMPNumTasksClause";
let flangClass = "OmpNumTasksClause";
Expand Down Expand Up @@ -366,8 +366,8 @@ def OMPC_OMPX_DynCGroupMem : Clause<"ompx_dyn_cgroup_mem"> {
let clangClass = "OMPXDynCGroupMemClause";
let flangClass = "ScalarIntExpr";
}
def OMP_ORDER_concurrent : ClauseVal<"concurrent",1,1> {}
def OMP_ORDER_unknown : ClauseVal<"unknown",2,0> { let isDefault = 1; }
def OMP_ORDER_concurrent : EnumVal<"concurrent",1,1> {}
def OMP_ORDER_unknown : EnumVal<"unknown",2,0> { let isDefault = 1; }
def OMPC_Order : Clause<"order"> {
let clangClass = "OMPOrderClause";
let flangClass = "OmpOrderClause";
Expand Down Expand Up @@ -404,12 +404,12 @@ def OMPC_Private : Clause<"private"> {
let clangClass = "OMPPrivateClause";
let flangClass = "OmpObjectList";
}
def OMP_PROC_BIND_master : ClauseVal<"master",2,1> {}
def OMP_PROC_BIND_close : ClauseVal<"close",3,1> {}
def OMP_PROC_BIND_spread : ClauseVal<"spread",4,1> {}
def OMP_PROC_BIND_primary : ClauseVal<"primary",5,1> {}
def OMP_PROC_BIND_default : ClauseVal<"default",6,0> {}
def OMP_PROC_BIND_unknown : ClauseVal<"unknown",7,0> { let isDefault = true; }
def OMP_PROC_BIND_master : EnumVal<"master",2,1> {}
def OMP_PROC_BIND_close : EnumVal<"close",3,1> {}
def OMP_PROC_BIND_spread : EnumVal<"spread",4,1> {}
def OMP_PROC_BIND_primary : EnumVal<"primary",5,1> {}
def OMP_PROC_BIND_default : EnumVal<"default",6,0> {}
def OMP_PROC_BIND_unknown : EnumVal<"unknown",7,0> { let isDefault = true; }
def OMPC_ProcBind : Clause<"proc_bind"> {
let clangClass = "OMPProcBindClause";
let flangClass = "OmpProcBindClause";
Expand Down Expand Up @@ -443,12 +443,12 @@ def OMPC_SafeLen : Clause<"safelen"> {
let clangClass = "OMPSafelenClause";
let flangClass = "ScalarIntConstantExpr";
}
def OMP_SCHEDULE_Static : ClauseVal<"static", 2, 1> {}
def OMP_SCHEDULE_Dynamic : ClauseVal<"dynamic", 3, 1> {}
def OMP_SCHEDULE_Guided : ClauseVal<"guided", 4, 1> {}
def OMP_SCHEDULE_Auto : ClauseVal<"auto", 5, 1> {}
def OMP_SCHEDULE_Runtime : ClauseVal<"runtime", 6, 1> {}
def OMP_SCHEDULE_Default : ClauseVal<"default", 7, 0> { let isDefault = 1; }
def OMP_SCHEDULE_Static : EnumVal<"static", 2, 1> {}
def OMP_SCHEDULE_Dynamic : EnumVal<"dynamic", 3, 1> {}
def OMP_SCHEDULE_Guided : EnumVal<"guided", 4, 1> {}
def OMP_SCHEDULE_Auto : EnumVal<"auto", 5, 1> {}
def OMP_SCHEDULE_Runtime : EnumVal<"runtime", 6, 1> {}
def OMP_SCHEDULE_Default : EnumVal<"default", 7, 0> { let isDefault = 1; }
def OMPC_Schedule : Clause<"schedule"> {
let clangClass = "OMPScheduleClause";
let flangClass = "OmpScheduleClause";
Expand Down
80 changes: 34 additions & 46 deletions llvm/include/llvm/TableGen/DirectiveEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,39 @@ class BaseRecord {

// Returns the name of the directive formatted for output. Whitespace are
// replaced with underscores.
static std::string formatName(StringRef Name) {
static std::string getSnakeName(StringRef Name) {
std::string N = Name.str();
llvm::replace(N, ' ', '_');
return N;
}

static std::string getUpperCamelName(StringRef Name, StringRef Sep) {
std::string Camel = Name.str();
// Convert to uppercase
bool Cap = true;
llvm::transform(Camel, Camel.begin(), [&](unsigned char C) {
if (Sep.contains(C)) {
assert(!Cap && "No initial or repeated separators");
Cap = true;
} else if (Cap) {
C = llvm::toUpper(C);
Cap = false;
}
return C;
});
size_t Out = 0;
// Remove separators
for (size_t In = 0, End = Camel.size(); In != End; ++In) {
unsigned char C = Camel[In];
if (!Sep.contains(C))
Camel[Out++] = C;
}
Camel.resize(Out);
return Camel;
}

std::string getFormattedName() const {
return formatName(Def->getValueAsString("name"));
return getSnakeName(Def->getValueAsString("name"));
}

bool isDefault() const { return Def->getValueAsBit("isDefault"); }
Expand Down Expand Up @@ -172,26 +197,13 @@ class Directive : public BaseRecord {

// Clang uses a different format for names of its directives enum.
std::string getClangAccSpelling() const {
std::string Name = Def->getValueAsString("name").str();
StringRef Name = Def->getValueAsString("name");

// Clang calls the 'unknown' value 'invalid'.
if (Name == "unknown")
return "Invalid";

// Clang entries all start with a capital letter, so apply that.
Name[0] = std::toupper(Name[0]);
// Additionally, spaces/underscores are handled by capitalizing the next
// letter of the name and removing the space/underscore.
for (unsigned I = 0; I < Name.size(); ++I) {
if (Name[I] == ' ' || Name[I] == '_') {
Name.erase(I, 1);
assert(Name[I] != ' ' && Name[I] != '_' &&
"No double spaces/underscores");
Name[I] = std::toupper(Name[I]);
}
}

return Name;
return BaseRecord::getUpperCamelName(Name, " _");
}
};

Expand All @@ -218,19 +230,7 @@ class Clause : public BaseRecord {
// num_threads -> NumThreads
std::string getFormattedParserClassName() const {
StringRef Name = Def->getValueAsString("name");
std::string N = Name.str();
bool Cap = true;
llvm::transform(N, N.begin(), [&Cap](unsigned char C) {
if (Cap == true) {
C = toUpper(C);
Cap = false;
} else if (C == '_') {
Cap = true;
}
return C;
});
erase(N, '_');
return N;
return BaseRecord::getUpperCamelName(Name, "_");
}

// Clang uses a different format for names of its clause enum, which can be
Expand All @@ -241,20 +241,8 @@ class Clause : public BaseRecord {
!ClangSpelling.empty())
return ClangSpelling.str();

std::string Name = Def->getValueAsString("name").str();
// Clang entries all start with a capital letter, so apply that.
Name[0] = std::toupper(Name[0]);
// Additionally, underscores are handled by capitalizing the next letter of
// the name and removing the underscore.
for (unsigned I = 0; I < Name.size(); ++I) {
if (Name[I] == '_') {
Name.erase(I, 1);
assert(Name[I] != '_' && "No double underscores");
Name[I] = std::toupper(Name[I]);
}
}

return Name;
StringRef Name = Def->getValueAsString("name");
return BaseRecord::getUpperCamelName(Name, "_");
}

// Optional field.
Expand Down Expand Up @@ -308,9 +296,9 @@ class VersionedClause {
const Record *Def;
};

class ClauseVal : public BaseRecord {
class EnumVal : public BaseRecord {
public:
ClauseVal(const Record *Def) : BaseRecord(Def) {}
EnumVal(const Record *Def) : BaseRecord(Def) {}

int getValue() const { return Def->getValueAsInt("value"); }

Expand Down
10 changes: 6 additions & 4 deletions llvm/test/TableGen/directive1.td
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ def TestDirectiveLanguage : DirectiveLanguage {
let flangClauseBaseClass = "TdlClause";
}

def TDLCV_vala : ClauseVal<"vala",1,1> {}
def TDLCV_valb : ClauseVal<"valb",2,1> {}
def TDLCV_valc : ClauseVal<"valc",3,0> { let isDefault = 1; }
def TDLCV_vala : EnumVal<"vala",1,1> {}
def TDLCV_valb : EnumVal<"valb",2,1> {}
def TDLCV_valc : EnumVal<"valc",3,0> { let isDefault = 1; }

def TDLC_ClauseA : Clause<"clausea"> {
let enumClauseValue = "AKind";
Expand All @@ -34,6 +34,7 @@ def TDLC_ClauseB : Clause<"clauseb"> {
}

def TDLC_ClauseC : Clause<"clausec"> {
let aliases = ["ccccccc"];
let flangClass = "IntExpr";
let isValueList = 1;
}
Expand Down Expand Up @@ -260,7 +261,8 @@ def TDL_DirA : Directive<"dira"> {
// IMPL-NEXT: TYPE_PARSER(
// IMPL-NEXT: "clausec" >> construct<TdlClause>(construct<TdlClause::Clausec>(parenthesized(nonemptyList(Parser<IntExpr>{})))) ||
// IMPL-NEXT: "clauseb" >> construct<TdlClause>(construct<TdlClause::Clauseb>(maybe(parenthesized(Parser<IntExpr>{})))) ||
// IMPL-NEXT: "clausea" >> construct<TdlClause>(construct<TdlClause::Clausea>())
// IMPL-NEXT: "clausea" >> construct<TdlClause>(construct<TdlClause::Clausea>()) ||
// IMPL-NEXT: "ccccccc" >> construct<TdlClause>(construct<TdlClause::Clausec>(parenthesized(nonemptyList(Parser<IntExpr>{}))))
// IMPL-NEXT: )
// IMPL-EMPTY:
// IMPL-NEXT: #endif // GEN_FLANG_CLAUSES_PARSER
Expand Down
Loading
Loading