Skip to content

Commit 304a345

Browse files
committed
Add optional type name override
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 304a345

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)