Skip to content

Commit ed4b46e

Browse files
Thomas Symallatsymalla-AMD
authored andcommitted
Add support for immutable strings.
We want a way to store strings in a global variable by passing in a StringRef to an op, but we don't want to generate a setter for it, since we currently don't inject the builder into the setter. So, add an immutable string type based on the existing isImmutable option for attributes.
1 parent ae1b86b commit ed4b46e

File tree

7 files changed

+156
-21
lines changed

7 files changed

+156
-21
lines changed

example/ExampleDialect.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,3 +317,13 @@ def ImmutableOp : Op<ExampleDialect, "immutable.op", [WillReturn]> {
317317
Make an argument immutable
318318
}];
319319
}
320+
321+
def StringAttrOp : Op<ExampleDialect, "string.attr.op", [WillReturn]> {
322+
let results = (outs);
323+
let arguments = (ins ImmutableStringAttr:$val);
324+
325+
let summary = "demonstrate an argument that takes in a StringRef";
326+
let description = [{
327+
The argument should not have a setter method
328+
}];
329+
}

example/ExampleMain.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ void createFunctionExample(Module &module, const Twine &name) {
141141
moreVarArgs.push_back(b.getInt32(4));
142142
b.create<xd::InstNameConflictVarargsOp>(moreVarArgs, "four.varargs");
143143

144+
b.create<xd::StringAttrOp>("Hello world!");
145+
144146
b.CreateRetVoid();
145147
}
146148

@@ -242,6 +244,10 @@ template <bool rpot> const Visitor<VisitorContainer> &getExampleVisitor() {
242244
for (Value *arg : op.getArgs())
243245
out << " " << *arg << '\n';
244246
});
247+
b.add<xd::StringAttrOp>(
248+
[](raw_ostream &out, xd::StringAttrOp &op) {
249+
out << "visiting StringAttrOp: " << op.getVal() << '\n';
250+
});
245251
b.add<ReturnInst>([](raw_ostream &out, ReturnInst &ret) {
246252
out << "visiting ReturnInst: " << ret << '\n';
247253
});

include/llvm-dialects/Dialect/Dialect.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,15 @@ def : AttrLlvmType<AttrI16, I16>;
279279
def : AttrLlvmType<AttrI32, I32>;
280280
def : AttrLlvmType<AttrI64, I64>;
281281

282+
def ImmutableStringAttr : Attr<"::llvm::StringRef"> {
283+
let toLlvmValue = [{ $_builder.CreateGlobalString($0) }];
284+
let fromLlvmValue = [{ ::llvm::cast<::llvm::ConstantDataArray>(::llvm::cast<::llvm::GlobalVariable>($0)->getInitializer())->getAsString() }];
285+
let isImmutable = true;
286+
}
287+
288+
// Global string variables are essentially pointers in addrspace(0).
289+
def : AttrLlvmType<ImmutableStringAttr, Ptr>;
290+
282291
// ============================================================================
283292
/// More general attributes
284293
// ============================================================================

test/example/generated/ExampleDialect.cpp.inc

Lines changed: 101 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ namespace xd {
129129
state.setError();
130130
});
131131

132+
builder.add<StringAttrOp>([](::llvm_dialects::VerifierState &state, StringAttrOp &op) {
133+
if (!op.verifier(state.out()))
134+
state.setError();
135+
});
136+
132137
builder.add<WriteOp>([](::llvm_dialects::VerifierState &state, WriteOp &op) {
133138
if (!op.verifier(state.out()))
134139
state.setError();
@@ -154,21 +159,21 @@ namespace xd {
154159
::llvm::AttrBuilder attrBuilder{context};
155160
attrBuilder.addAttribute(::llvm::Attribute::NoUnwind);
156161
attrBuilder.addAttribute(::llvm::Attribute::WillReturn);
157-
attrBuilder.addMemoryAttr(::llvm::MemoryEffects(::llvm::ModRefInfo::Ref));
162+
attrBuilder.addMemoryAttr(::llvm::MemoryEffects::none());
158163
m_attributeLists[0] = ::llvm::AttributeList::get(context, ::llvm::AttributeList::FunctionIndex, attrBuilder);
159164
}
160165
{
161166
::llvm::AttrBuilder attrBuilder{context};
162167
attrBuilder.addAttribute(::llvm::Attribute::NoUnwind);
163168
attrBuilder.addAttribute(::llvm::Attribute::WillReturn);
164-
attrBuilder.addMemoryAttr(::llvm::MemoryEffects(::llvm::MemoryEffects::Location::InaccessibleMem, ::llvm::ModRefInfo::Mod));
169+
attrBuilder.addMemoryAttr(::llvm::MemoryEffects(::llvm::ModRefInfo::Ref));
165170
m_attributeLists[1] = ::llvm::AttributeList::get(context, ::llvm::AttributeList::FunctionIndex, attrBuilder);
166171
}
167172
{
168173
::llvm::AttrBuilder attrBuilder{context};
169174
attrBuilder.addAttribute(::llvm::Attribute::NoUnwind);
170175
attrBuilder.addAttribute(::llvm::Attribute::WillReturn);
171-
attrBuilder.addMemoryAttr(::llvm::MemoryEffects::none());
176+
attrBuilder.addMemoryAttr(::llvm::MemoryEffects(::llvm::MemoryEffects::Location::InaccessibleMem, ::llvm::ModRefInfo::Mod));
172177
m_attributeLists[2] = ::llvm::AttributeList::get(context, ::llvm::AttributeList::FunctionIndex, attrBuilder);
173178
}
174179
{
@@ -329,7 +334,7 @@ return true;
329334

330335

331336
const ::llvm::AttributeList attrs
332-
= ExampleDialect::get(context).getAttributeList(2);
337+
= ExampleDialect::get(context).getAttributeList(0);
333338
auto fnType = ::llvm::FunctionType::get(::llvm::IntegerType::get(context, 32), {
334339
lhs->getType(),
335340
rhs->getType(),
@@ -451,7 +456,7 @@ uint32_t const extra = getExtra();
451456

452457

453458
const ::llvm::AttributeList attrs
454-
= ExampleDialect::get(context).getAttributeList(2);
459+
= ExampleDialect::get(context).getAttributeList(0);
455460

456461
std::string mangledName =
457462
::llvm_dialects::getMangledName(s_name, {lhs->getType()});
@@ -546,7 +551,7 @@ rhs
546551

547552

548553
const ::llvm::AttributeList attrs
549-
= ExampleDialect::get(context).getAttributeList(2);
554+
= ExampleDialect::get(context).getAttributeList(0);
550555

551556
std::string mangledName =
552557
::llvm_dialects::getMangledName(s_name, {::llvm::cast<XdVectorType>(vector->getType())->getElementType()});
@@ -650,7 +655,7 @@ index
650655

651656

652657
const ::llvm::AttributeList attrs
653-
= ExampleDialect::get(context).getAttributeList(2);
658+
= ExampleDialect::get(context).getAttributeList(0);
654659

655660
std::string mangledName =
656661
::llvm_dialects::getMangledName(s_name, {resultType});
@@ -820,7 +825,7 @@ source
820825

821826

822827
const ::llvm::AttributeList attrs
823-
= ExampleDialect::get(context).getAttributeList(2);
828+
= ExampleDialect::get(context).getAttributeList(0);
824829
auto fnType = ::llvm::FunctionType::get(XdHandleType::get(context), {
825830
}, false);
826831

@@ -882,7 +887,7 @@ source
882887

883888

884889
const ::llvm::AttributeList attrs
885-
= ExampleDialect::get(context).getAttributeList(2);
890+
= ExampleDialect::get(context).getAttributeList(0);
886891

887892
std::string mangledName =
888893
::llvm_dialects::getMangledName(s_name, {resultType});
@@ -980,7 +985,7 @@ source
980985

981986

982987
const ::llvm::AttributeList attrs
983-
= ExampleDialect::get(context).getAttributeList(2);
988+
= ExampleDialect::get(context).getAttributeList(0);
984989

985990
std::string mangledName =
986991
::llvm_dialects::getMangledName(s_name, {resultType});
@@ -1113,7 +1118,7 @@ source
11131118
(void)context;
11141119

11151120
using ::llvm_dialects::printable;
1116-
1121+
11171122
if (arg_size() != 1) {
11181123
errs << " wrong number of arguments: " << arg_size()
11191124
<< ", expected 1\n";
@@ -1147,7 +1152,7 @@ source
11471152

11481153

11491154
const ::llvm::AttributeList attrs
1150-
= ExampleDialect::get(context).getAttributeList(2);
1155+
= ExampleDialect::get(context).getAttributeList(0);
11511156

11521157
std::string mangledName =
11531158
::llvm_dialects::getMangledName(s_name, {vector->getType()});
@@ -1607,7 +1612,7 @@ instName
16071612

16081613

16091614
const ::llvm::AttributeList attrs
1610-
= ExampleDialect::get(context).getAttributeList(1);
1615+
= ExampleDialect::get(context).getAttributeList(2);
16111616
auto fnType = ::llvm::FunctionType::get(::llvm::Type::getVoidTy(context), true);
16121617

16131618
auto fn = module.getOrInsertFunction(s_name, fnType, attrs);
@@ -1670,7 +1675,7 @@ data
16701675

16711676

16721677
const ::llvm::AttributeList attrs
1673-
= ExampleDialect::get(context).getAttributeList(2);
1678+
= ExampleDialect::get(context).getAttributeList(0);
16741679
auto fnType = ::llvm::FunctionType::get(::llvm::IntegerType::get(context, 64), true);
16751680

16761681
auto fn = module.getOrInsertFunction(s_name, fnType, attrs);
@@ -1744,7 +1749,7 @@ data
17441749

17451750

17461751
const ::llvm::AttributeList attrs
1747-
= ExampleDialect::get(context).getAttributeList(0);
1752+
= ExampleDialect::get(context).getAttributeList(1);
17481753

17491754
std::string mangledName =
17501755
::llvm_dialects::getMangledName(s_name, {initial->getType()});
@@ -1836,7 +1841,7 @@ initial
18361841

18371842

18381843
const ::llvm::AttributeList attrs
1839-
= ExampleDialect::get(context).getAttributeList(0);
1844+
= ExampleDialect::get(context).getAttributeList(1);
18401845

18411846
std::string mangledName =
18421847
::llvm_dialects::getMangledName(s_name, {initial->getType()});
@@ -1928,7 +1933,7 @@ initial
19281933

19291934

19301935
const ::llvm::AttributeList attrs
1931-
= ExampleDialect::get(context).getAttributeList(0);
1936+
= ExampleDialect::get(context).getAttributeList(1);
19321937

19331938
std::string mangledName =
19341939
::llvm_dialects::getMangledName(s_name, {initial->getType()});
@@ -2011,6 +2016,75 @@ initial
20112016

20122017

20132018

2019+
const ::llvm::StringLiteral StringAttrOp::s_name{"xd.string.attr.op"};
2020+
2021+
StringAttrOp* StringAttrOp::create(llvm_dialects::Builder& b, ::llvm::StringRef val, const llvm::Twine &instName) {
2022+
::llvm::LLVMContext& context = b.getContext();
2023+
(void)context;
2024+
::llvm::Module& module = *b.GetInsertBlock()->getModule();
2025+
2026+
2027+
const ::llvm::AttributeList attrs
2028+
= ExampleDialect::get(context).getAttributeList(4);
2029+
auto fnType = ::llvm::FunctionType::get(::llvm::Type::getVoidTy(context), {
2030+
::llvm::PointerType::get(::llvm::Type::getInt8Ty(context), 0),
2031+
}, false);
2032+
2033+
auto fn = module.getOrInsertFunction(s_name, fnType, attrs);
2034+
::llvm::SmallString<32> newName;
2035+
for (unsigned i = 0; !::llvm::isa<::llvm::Function>(fn.getCallee()) ||
2036+
::llvm::cast<::llvm::Function>(fn.getCallee())->getFunctionType() != fn.getFunctionType(); i++) {
2037+
// If a function with the same name but a different types already exists,
2038+
// we get a bitcast of a function or a function with the wrong type.
2039+
// Try new names until we get one with the correct type.
2040+
newName = "";
2041+
::llvm::raw_svector_ostream newNameStream(newName);
2042+
newNameStream << s_name << "_" << i;
2043+
fn = module.getOrInsertFunction(newNameStream.str(), fnType, attrs);
2044+
}
2045+
assert(::llvm::isa<::llvm::Function>(fn.getCallee()));
2046+
assert(fn.getFunctionType() == fnType);
2047+
assert(::llvm::cast<::llvm::Function>(fn.getCallee())->getFunctionType() == fn.getFunctionType());
2048+
2049+
2050+
::llvm::SmallVector<::llvm::Value*, 1> args = {
2051+
b.CreateGlobalString(val)
2052+
};
2053+
2054+
return ::llvm::cast<StringAttrOp>(b.CreateCall(fn, args, instName));
2055+
}
2056+
2057+
2058+
bool StringAttrOp::verifier(::llvm::raw_ostream &errs) {
2059+
::llvm::LLVMContext &context = getModule()->getContext();
2060+
(void)context;
2061+
2062+
using ::llvm_dialects::printable;
2063+
2064+
if (arg_size() != 1) {
2065+
errs << " wrong number of arguments: " << arg_size()
2066+
<< ", expected 1\n";
2067+
return false;
2068+
}
2069+
2070+
if (getArgOperand(0)->getType() != ::llvm::PointerType::get(::llvm::Type::getInt8Ty(context), 0)) {
2071+
errs << " argument 0 (val) has type: "
2072+
<< *getArgOperand(0)->getType() << '\n';
2073+
errs << " expected: " << *::llvm::PointerType::get(::llvm::Type::getInt8Ty(context), 0) << '\n';
2074+
return false;
2075+
}
2076+
::llvm::StringRef const val = getVal();
2077+
(void)val;
2078+
return true;
2079+
}
2080+
2081+
2082+
::llvm::StringRef StringAttrOp::getVal() {
2083+
return ::llvm::cast<::llvm::ConstantDataArray>(::llvm::cast<::llvm::GlobalVariable>(getArgOperand(0))->getInitializer())->getAsString() ;
2084+
}
2085+
2086+
2087+
20142088
const ::llvm::StringLiteral WriteOp::s_name{"xd.write"};
20152089

20162090
WriteOp* WriteOp::create(llvm_dialects::Builder& b, ::llvm::Value * data, const llvm::Twine &instName) {
@@ -2020,7 +2094,7 @@ initial
20202094

20212095

20222096
const ::llvm::AttributeList attrs
2023-
= ExampleDialect::get(context).getAttributeList(1);
2097+
= ExampleDialect::get(context).getAttributeList(2);
20242098
auto fnType = ::llvm::FunctionType::get(::llvm::Type::getVoidTy(context), true);
20252099

20262100
auto fn = module.getOrInsertFunction(s_name, fnType, attrs);
@@ -2083,7 +2157,7 @@ data
20832157

20842158

20852159
const ::llvm::AttributeList attrs
2086-
= ExampleDialect::get(context).getAttributeList(1);
2160+
= ExampleDialect::get(context).getAttributeList(2);
20872161
auto fnType = ::llvm::FunctionType::get(::llvm::Type::getVoidTy(context), true);
20882162

20892163
auto fn = module.getOrInsertFunction(s_name, fnType, attrs);
@@ -2297,6 +2371,14 @@ data
22972371
}
22982372

22992373

2374+
template <>
2375+
const ::llvm_dialects::OpDescription &
2376+
::llvm_dialects::OpDescription::get<xd::StringAttrOp>() {
2377+
static const ::llvm_dialects::OpDescription desc{false, "xd.string.attr.op"};
2378+
return desc;
2379+
}
2380+
2381+
23002382
template <>
23012383
const ::llvm_dialects::OpDescription &
23022384
::llvm_dialects::OpDescription::get<xd::WriteOp>() {

test/example/generated/ExampleDialect.h.inc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,26 @@ bool verifier(::llvm::raw_ostream &errs);
535535
::llvm::Value * getResult();
536536

537537

538+
};
539+
540+
class StringAttrOp : public ::llvm::CallInst {
541+
static const ::llvm::StringLiteral s_name; //{"xd.string.attr.op"};
542+
543+
public:
544+
static bool classof(const ::llvm::CallInst* i) {
545+
return ::llvm_dialects::detail::isSimpleOperation(i, s_name);
546+
}
547+
static bool classof(const ::llvm::Value* v) {
548+
return ::llvm::isa<::llvm::CallInst>(v) &&
549+
classof(::llvm::cast<::llvm::CallInst>(v));
550+
}
551+
static StringAttrOp* create(::llvm_dialects::Builder& b, ::llvm::StringRef val, const llvm::Twine &instName = "");
552+
553+
bool verifier(::llvm::raw_ostream &errs);
554+
555+
::llvm::StringRef getVal();
556+
557+
538558
};
539559

540560
class WriteOp : public ::llvm::CallInst {

test/example/test-builder.test

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --tool llvm-dialects-example --include-generated-funcs
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --tool llvm-dialects-example --include-generated-funcs --check-globals
22
; NOTE: stdin isn't used by the example program, but the redirect makes the UTC tool happy.
33
; RUN: llvm-dialects-example - | FileCheck --check-prefixes=CHECK %s
44

5+
;.
6+
; CHECK: @[[GLOB0:[0-9]+]] = private unnamed_addr constant [13 x i8] c"Hello world!\00", align 1
7+
;.
58
; CHECK-LABEL: @example(
69
; CHECK-NEXT: entry:
710
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @xd.read__i32()
@@ -42,5 +45,6 @@
4245
; CHECK-NEXT: [[TWO_VARARGS:%.*]] = call i32 (...) @xd.inst.name.conflict.varargs(ptr [[P1]], i8 [[P2]])
4346
; CHECK-NEXT: [[THREE_VARARGS:%.*]] = call i32 (...) @xd.inst.name.conflict.varargs(ptr [[P1]], i8 [[P2]], i32 3)
4447
; CHECK-NEXT: [[FOUR_VARARGS:%.*]] = call i32 (...) @xd.inst.name.conflict.varargs(ptr [[P1]], i8 [[P2]], i32 3, i32 4)
48+
; CHECK-NEXT: call void @xd.string.attr.op(ptr @[[GLOB0:[0-9]+]])
4549
; CHECK-NEXT: ret void
4650
;

test/example/visitor-basic.ll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616
; DEFAULT-NEXT: %v2 =
1717
; DEFAULT-NEXT: %q =
1818
; DEFAULT-NEXT: visiting umin (set): %vm = call i32 @llvm.umin.i32(i32 %v1, i32 %q)
19+
; DEFAULT-NEXT: visiting StringAttrOp: Hello world!
1920
; DEFAULT-NEXT: visiting Ret (set): ret void
2021
; DEFAULT-NEXT: visiting ReturnInst: ret void
2122
; DEFAULT-NEXT: inner.counter = 1
2223

24+
@0 = private unnamed_addr constant [13 x i8] c"Hello world!\00", align 1
25+
2326
define void @test1(ptr %p) {
2427
entry:
2528
%v = call i32 @xd.read__i32()
@@ -36,6 +39,7 @@ entry:
3639
call void (...) @xd.set.write(i8 %v.2)
3740
call void (...) @xd.write.vararg(i8 %t, i32 %v2, i32 %q)
3841
%vm = call i32 @llvm.umin.i32(i32 %v1, i32 %q)
42+
call void @xd.string.attr.op(ptr @0)
3943
ret void
4044
}
4145

@@ -46,6 +50,6 @@ declare void @xd.write(...)
4650
declare void @xd.set.write(...)
4751
declare void @xd.write.vararg(...)
4852
declare i8 @xd.itrunc__i8(...)
49-
53+
declare void @xd.string.attr.op(ptr)
5054
declare i32 @llvm.umax.i32(i32, i32)
5155
declare i32 @llvm.umin.i32(i32, i32)

0 commit comments

Comments
 (0)