Skip to content

Commit 72b76fa

Browse files
authored
Add optional type name override (#135)
Add llvmTypeNameOverride property to DialectType to allow overriding the LLVM IR type name generated for dialect types. This is useful when the natural dialect+mnemonic name does not match backend conventions.
1 parent f6f1a2e commit 72b76fa

File tree

7 files changed

+204
-5
lines changed

7 files changed

+204
-5
lines changed

include/llvm-dialects/Dialect/Dialect.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ class DialectType<Dialect dialect_, string mnemonic_> : Type, Predicate {
239239
/// discriminant; the discriminant should be a type that cannot naturally
240240
/// appear elsewhere, e.g. (repr_struct (IntegerType 41))
241241
dag representation = (repr_targetext);
242+
243+
/// Optional custom name for the LLVM IR type. If not set, defaults to
244+
/// "<dialect>.<mnemonic>".
245+
string llvmTypeNameOverride = "";
242246
}
243247

244248
def and;

include/llvm-dialects/TableGen/DialectType.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ class DialectType : public BaseCppPredicate {
4646
RecordTy *getDialectRec() const { return m_dialectRec; }
4747
llvm::StringRef getName() const { return m_name; }
4848
llvm::StringRef getMnemonic() const { return m_mnemonic; }
49+
llvm::StringRef getLlvmTypeNameOverride() const {
50+
return m_llvmTypeNameOverride;
51+
}
4952
bool defaultGetterHasExplicitContextArgument() const {
5053
return m_defaultGetterHasExplicitContextArgument;
5154
}
@@ -64,6 +67,7 @@ class DialectType : public BaseCppPredicate {
6467
RecordTy *m_dialectRec = nullptr;
6568
std::string m_name;
6669
std::string m_mnemonic;
70+
std::string m_llvmTypeNameOverride;
6771
bool m_defaultGetterHasExplicitContextArgument = false;
6872
std::string m_summary;
6973
std::string m_description;

lib/TableGen/DialectType.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ bool DialectType::init(raw_ostream &errs, GenDialectsContext &context,
4343
m_mnemonic = record->getValueAsString("mnemonic");
4444
m_summary = record->getValueAsString("summary");
4545
m_description = record->getValueAsString("description");
46+
m_llvmTypeNameOverride = record->getValueAsString("llvmTypeNameOverride");
4647

4748
if (auto *dag =
4849
cast<DagInit>(record->getValue("representation")->getValue())) {
@@ -170,12 +171,25 @@ void DialectType::emitDeclaration(raw_ostream &out, GenDialect *dialect) const {
170171
fmt.addSubst("_type", getName());
171172
fmt.addSubst("mnemonic", getMnemonic());
172173

174+
std::string typeName;
175+
if (!m_llvmTypeNameOverride.empty()) {
176+
typeName = m_llvmTypeNameOverride;
177+
} else {
178+
typeName = (dialect->name + "." + getMnemonic()).str();
179+
}
180+
// For struct-backed types, add trailing dot for the prefix
181+
if (m_structBacked) {
182+
typeName += ".";
183+
}
184+
185+
fmt.addSubst("typeName", typeName);
186+
173187
if (m_structBacked) {
174188
out << tgfmt(R"(
175189
class $_type : public ::llvm::StructType {
176190
using ::llvm::StructType::StructType;
177191
public:
178-
static constexpr ::llvm::StringLiteral s_prefix{"$dialect.$mnemonic."};
192+
static constexpr ::llvm::StringLiteral s_prefix{"$typeName"};
179193
180194
using ::llvm::StructType::getElementType;
181195
@@ -225,10 +239,11 @@ void DialectType::emitDeclaration(raw_ostream &out, GenDialect *dialect) const {
225239
} else {
226240

227241
// TargetExtType
242+
fmt.addSubst("typeName", typeName);
228243

229244
out << tgfmt(R"(
230245
class $_type : public ::llvm::TargetExtType {
231-
static constexpr ::llvm::StringLiteral s_name{"$dialect.$mnemonic"};
246+
static constexpr ::llvm::StringLiteral s_name{"$typeName"};
232247
233248
public:
234249
static bool classof(const ::llvm::TargetExtType *t) {
@@ -276,6 +291,14 @@ void DialectType::emitDefinition(raw_ostream &out, GenDialect *dialect) const {
276291
fmt.addSubst("fields", symbols.chooseName("fields"));
277292
fmt.addSubst("st", symbols.chooseName("st"));
278293

294+
// Compute the type name prefix (without trailing dot for struct-backed types)
295+
std::string typeNamePrefix;
296+
if (!m_llvmTypeNameOverride.empty()) {
297+
typeNamePrefix = m_llvmTypeNameOverride;
298+
} else {
299+
typeNamePrefix = (dialect->name + "." + getMnemonic()).str();
300+
}
301+
279302
if (m_structBacked) {
280303
out << tgfmt("$_type* $_type::get(", &fmt);
281304
bool contextPresent =
@@ -305,7 +328,7 @@ void DialectType::emitDefinition(raw_ostream &out, GenDialect *dialect) const {
305328

306329
out << tgfmt(
307330
" std::string $name; ::llvm::raw_string_ostream $os($name);\n", &fmt);
308-
out << tgfmt(" $os << \"$0\";\n", &fmt, m_mnemonic);
331+
out << tgfmt(" $os << \"$0\";\n", &fmt, typeNamePrefix);
309332
for (const auto &getterArg : getterArgs)
310333
out << tgfmt(" $os << '.' << (uint64_t)$0;\n", &fmt, getterArg.name);
311334

test/example/generated/ExampleDialect.cpp.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ StructBackedType* StructBackedType::get(::llvm::LLVMContext & ctx, uint32_t fiel
263263

264264
static_assert(sizeof(field2) <= sizeof(unsigned));
265265
std::string name; ::llvm::raw_string_ostream os(name);
266-
os << "struct.backed";
266+
os << "xd.ir.struct.backed";
267267
os << '.' << (uint64_t)field0;
268268
os << '.' << (uint64_t)field1;
269269
os << '.' << (uint64_t)field2;

test/unit/dialect/TestDialect.td

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,56 @@ def InstNameConflictWithExplRetTestOp : Op<TestDialect, "try.conflict.type.suffi
8282
value like IRBuilder methods. This op tries to produce a conflict
8383
}];
8484
}
85+
86+
// Test types with custom llvmTypeNameOverride
87+
88+
// Test TargetExtType with custom name
89+
def CustomNameTargetExtType : DialectType<TestDialect, "custom.target"> {
90+
let typeArguments = (args
91+
AttrI32:$param1,
92+
AttrI32:$param2
93+
);
94+
95+
let defaultGetterHasExplicitContextArgument = true;
96+
let llvmTypeNameOverride = "custom.renamed.target";
97+
98+
let summary = "TargetExtType with custom name";
99+
let description = [{
100+
Tests that llvmTypeNameOverride works for TargetExtType.
101+
Type name should be "custom.renamed.target" instead of "test.custom.target".
102+
}];
103+
}
104+
105+
// Test struct-backed type with custom name prefix
106+
def CustomNameStructType : DialectType<TestDialect, "custom.struct"> {
107+
let typeArguments = (args
108+
AttrI32:$rows,
109+
AttrI32:$cols
110+
);
111+
112+
let defaultGetterHasExplicitContextArgument = true;
113+
let representation = (repr_struct (IntegerType 73));
114+
let llvmTypeNameOverride = "custom.renamed.struct";
115+
116+
let summary = "Struct-backed type with custom name prefix";
117+
let description = [{
118+
Tests that llvmTypeNameOverride works for struct-backed types.
119+
Type name prefix should be "custom.renamed.struct." instead of "test.custom.struct.".
120+
The trailing dot is automatically added for struct types.
121+
}];
122+
}
123+
124+
// Test TargetExtType without custom name (default behavior)
125+
def DefaultNameTargetExtType : DialectType<TestDialect, "default.target"> {
126+
let typeArguments = (args
127+
AttrI32:$value
128+
);
129+
130+
let defaultGetterHasExplicitContextArgument = true;
131+
132+
let summary = "TargetExtType with default name";
133+
let description = [{
134+
Tests default naming behavior for TargetExtType.
135+
Type name should be "test.default.target".
136+
}];
137+
}

test/unit/interface/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
add_dialects_unit_test(DialectsADTTests
2121
OpSetTests.cpp
2222
OpMapTests.cpp
23-
OpMapIRTests.cpp)
23+
OpMapIRTests.cpp
24+
DialectTypeTests.cpp)
2425

2526
add_dependencies(DialectsADTTests TestDialectTableGen)
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
***********************************************************************************************************************
3+
* Copyright (c) 2026 Advanced Micro Devices, Inc. All Rights Reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
***********************************************************************************************************************
17+
*/
18+
19+
#include "TestDialect.h"
20+
#include "llvm/IR/LLVMContext.h"
21+
#include "llvm/IR/Type.h"
22+
#include "gtest/gtest.h"
23+
24+
using namespace llvm;
25+
using namespace test;
26+
27+
// Test custom llvmTypeNameOverride for TargetExtType
28+
TEST(DialectTypeTest, CustomNameTargetExtType) {
29+
LLVMContext ctx;
30+
31+
auto *type = CustomNameTargetExtType::get(ctx, 10, 20);
32+
ASSERT_NE(type, nullptr);
33+
34+
// Verify it's recognized as the correct type via classof
35+
EXPECT_TRUE(isa<CustomNameTargetExtType>(type));
36+
EXPECT_TRUE(CustomNameTargetExtType::classof(type));
37+
38+
// Verify the type name is the custom one, not the default
39+
auto *targetExtType = cast<TargetExtType>(type);
40+
EXPECT_EQ(targetExtType->getName(), "custom.renamed.target");
41+
42+
// Verify parameters are accessible
43+
EXPECT_EQ(type->getParam1(), 10u);
44+
EXPECT_EQ(type->getParam2(), 20u);
45+
}
46+
47+
// Test custom llvmTypeNameOverride for struct-backed type
48+
TEST(DialectTypeTest, CustomNameStructType) {
49+
LLVMContext ctx;
50+
51+
auto *type = CustomNameStructType::get(ctx, 16, 16);
52+
ASSERT_NE(type, nullptr);
53+
54+
// Verify it's recognized as the correct type via classof
55+
EXPECT_TRUE(isa<CustomNameStructType>(type));
56+
EXPECT_TRUE(CustomNameStructType::classof(type));
57+
58+
// Verify the struct type name has the custom prefix
59+
auto *structType = cast<StructType>(type);
60+
EXPECT_TRUE(structType->getName().starts_with("custom.renamed.struct."));
61+
62+
// Verify parameters are accessible
63+
EXPECT_EQ(type->getRows(), 16u);
64+
EXPECT_EQ(type->getCols(), 16u);
65+
}
66+
67+
// Test default naming behavior (no llvmTypeNameOverride specified)
68+
TEST(DialectTypeTest, DefaultNameTargetExtType) {
69+
LLVMContext ctx;
70+
71+
auto *type = DefaultNameTargetExtType::get(ctx, 42);
72+
ASSERT_NE(type, nullptr);
73+
74+
// Verify it's recognized as the correct type
75+
EXPECT_TRUE(isa<DefaultNameTargetExtType>(type));
76+
EXPECT_TRUE(DefaultNameTargetExtType::classof(type));
77+
78+
// Verify the type name uses the default dialect.mnemonic format
79+
auto *targetExtType = cast<TargetExtType>(type);
80+
EXPECT_EQ(targetExtType->getName(), "test.default.target");
81+
82+
// Verify parameter is accessible
83+
EXPECT_EQ(type->getValue(), 42u);
84+
}
85+
86+
// Test that different custom types are distinguishable
87+
TEST(DialectTypeTest, TypeDistinction) {
88+
LLVMContext ctx;
89+
90+
auto *customTarget = CustomNameTargetExtType::get(ctx, 1, 2);
91+
auto *defaultTarget = DefaultNameTargetExtType::get(ctx, 3);
92+
auto *customStruct = CustomNameStructType::get(ctx, 4, 5);
93+
94+
// Types should be distinct
95+
EXPECT_NE(static_cast<llvm::Type *>(customTarget),
96+
static_cast<llvm::Type *>(defaultTarget));
97+
EXPECT_NE(static_cast<llvm::Type *>(customTarget),
98+
static_cast<llvm::Type *>(customStruct));
99+
EXPECT_NE(static_cast<llvm::Type *>(defaultTarget),
100+
static_cast<llvm::Type *>(customStruct));
101+
102+
// classof should work correctly
103+
EXPECT_TRUE(CustomNameTargetExtType::classof(customTarget));
104+
EXPECT_FALSE(CustomNameTargetExtType::classof(defaultTarget));
105+
EXPECT_FALSE(CustomNameTargetExtType::classof(customStruct));
106+
107+
EXPECT_FALSE(DefaultNameTargetExtType::classof(customTarget));
108+
EXPECT_TRUE(DefaultNameTargetExtType::classof(defaultTarget));
109+
EXPECT_FALSE(DefaultNameTargetExtType::classof(customStruct));
110+
111+
EXPECT_FALSE(CustomNameStructType::classof(customTarget));
112+
EXPECT_FALSE(CustomNameStructType::classof(defaultTarget));
113+
EXPECT_TRUE(CustomNameStructType::classof(customStruct));
114+
}

0 commit comments

Comments
 (0)