Skip to content

Commit 37af6cb

Browse files
authored
Merge pull request #269 from maleadt/tb/operand_bundles
Add support for inspecting and creating operand bundles.
2 parents a1a2aa6 + 246368b commit 37af6cb

File tree

9 files changed

+403
-10
lines changed

9 files changed

+403
-10
lines changed

Manifest.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ version = "1.3.0"
3434

3535
[[LLVMExtra_jll]]
3636
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
37-
git-tree-sha1 = "9c360e5ce980b88bb31a7b086dbb19469008154b"
37+
git-tree-sha1 = "6a2af408fe809c4f1a54d2b3f188fdd3698549d6"
3838
uuid = "dad2f222-ce93-54a1-a47d-0025e8a3acab"
39-
version = "0.0.10+0"
39+
version = "0.0.11+0"
4040

4141
[[LibCURL]]
4242
deps = ["LibCURL_jll", "MozillaCACerts_jll"]

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
1111

1212
[compat]
1313
CEnum = "0.2, 0.3, 0.4"
14-
LLVMExtra_jll = "~0.0.10"
14+
LLVMExtra_jll = "~0.0.11"
1515
julia = "1.6"

deps/LLVMExtra/include/LLVMExtra.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,5 +135,27 @@ void LLVMFunctionDeleteBody(LLVMValueRef Func);
135135

136136
void LLVMDestroyConstant(LLVMValueRef Const);
137137

138+
// operand bundles
139+
typedef struct LLVMOpaqueOperandBundleUse *LLVMOperandBundleUseRef;
140+
unsigned LLVMGetNumOperandBundles(LLVMValueRef Instr);
141+
LLVMOperandBundleUseRef LLVMGetOperandBundle(LLVMValueRef Val, unsigned Index);
142+
void LLVMDisposeOperandBundleUse(LLVMOperandBundleUseRef Bundle);
143+
uint32_t LLVMGetOperandBundleUseTagID(LLVMOperandBundleUseRef Bundle);
144+
const char *LLVMGetOperandBundleUseTagName(LLVMOperandBundleUseRef Bundle, unsigned *Length);
145+
unsigned LLVMGetOperandBundleUseNumInputs(LLVMOperandBundleUseRef Bundle);
146+
void LLVMGetOperandBundleUseInputs(LLVMOperandBundleUseRef Bundle, LLVMValueRef *Dest);
147+
typedef struct LLVMOpaqueOperandBundleDef *LLVMOperandBundleDefRef;
148+
LLVMOperandBundleDefRef LLVMOperandBundleDefFromUse(LLVMOperandBundleUseRef Bundle);
149+
LLVMOperandBundleDefRef LLVMCreateOperandBundleDef(const char *Tag, LLVMValueRef *Inputs,
150+
unsigned NumInputs);
151+
void LLVMDisposeOperandBundleDef(LLVMOperandBundleDefRef Bundle);
152+
const char *LLVMGetOperandBundleDefTag(LLVMOperandBundleDefRef Bundle, unsigned *Length);
153+
unsigned LLVMGetOperandBundleDefNumInputs(LLVMOperandBundleDefRef Bundle);
154+
void LLVMGetOperandBundleDefInputs(LLVMOperandBundleDefRef Bundle, LLVMValueRef *Dest);
155+
LLVMValueRef LLVMBuildCallWithOpBundle(LLVMBuilderRef B, LLVMValueRef Fn,
156+
LLVMValueRef *Args, unsigned NumArgs,
157+
LLVMOperandBundleDefRef *Bundles, unsigned NumBundles,
158+
const char *Name);
159+
138160
LLVM_C_EXTERN_C_END
139161
#endif

deps/LLVMExtra/lib/llvm-api.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <llvm/IR/GlobalValue.h>
1010
#include <llvm/IR/Instruction.h>
1111
#include <llvm/IR/Instructions.h>
12+
#include <llvm/IR/IRBuilder.h>
1213
#include <llvm/IR/LegacyPassManager.h>
1314
#include <llvm/IR/Module.h>
1415
#include <llvm/Support/TargetSelect.h>
@@ -422,3 +423,93 @@ void LLVMFunctionDeleteBody(LLVMValueRef Func) {
422423
void LLVMDestroyConstant(LLVMValueRef Const) {
423424
unwrap<Constant>(Const)->destroyConstant();
424425
}
426+
427+
// operand bundles
428+
429+
DEFINE_STDCXX_CONVERSION_FUNCTIONS(OperandBundleUse, LLVMOperandBundleUseRef)
430+
431+
unsigned LLVMGetNumOperandBundles(LLVMValueRef Instr) {
432+
return unwrap<CallBase>(Instr)->getNumOperandBundles();
433+
}
434+
435+
LLVMOperandBundleUseRef LLVMGetOperandBundle(LLVMValueRef Val, unsigned Index) {
436+
CallBase *CB = unwrap<CallBase>(Val);
437+
return wrap(new OperandBundleUse(CB->getOperandBundleAt(Index)));
438+
}
439+
440+
void LLVMDisposeOperandBundleUse(LLVMOperandBundleUseRef Bundle) {
441+
delete unwrap<OperandBundleUse>(Bundle);
442+
return;
443+
}
444+
445+
uint32_t LLVMGetOperandBundleUseTagID(LLVMOperandBundleUseRef Bundle) {
446+
const OperandBundleUse *S = unwrap<OperandBundleUse>(Bundle);
447+
return S->getTagID();
448+
}
449+
450+
const char *LLVMGetOperandBundleUseTagName(LLVMOperandBundleUseRef Bundle, unsigned *Length) {
451+
const OperandBundleUse *S = unwrap<OperandBundleUse>(Bundle);
452+
*Length = S->getTagName().size();
453+
return S->getTagName().data();
454+
}
455+
456+
unsigned LLVMGetOperandBundleUseNumInputs(LLVMOperandBundleUseRef Bundle) {
457+
return unwrap<OperandBundleUse>(Bundle)->Inputs.size();
458+
}
459+
460+
void LLVMGetOperandBundleUseInputs(LLVMOperandBundleUseRef Bundle, LLVMValueRef *Dest) {
461+
size_t i = 0;
462+
for (auto &input: unwrap<OperandBundleUse>(Bundle)->Inputs)
463+
Dest[i++] = wrap(input);
464+
}
465+
466+
DEFINE_STDCXX_CONVERSION_FUNCTIONS(OperandBundleDef, LLVMOperandBundleDefRef)
467+
468+
LLVMOperandBundleDefRef LLVMCreateOperandBundleDef(const char *Tag, LLVMValueRef *Inputs,
469+
unsigned NumInputs) {
470+
SmallVector<Value*, 1> InputArray;
471+
for (auto *Input : makeArrayRef(Inputs, NumInputs))
472+
InputArray.push_back(unwrap(Input));
473+
return wrap(new OperandBundleDef(std::string(Tag), InputArray));
474+
}
475+
476+
LLVMOperandBundleDefRef LLVMOperandBundleDefFromUse(LLVMOperandBundleUseRef Bundle) {
477+
return wrap(new OperandBundleDef(*unwrap<OperandBundleUse>(Bundle)));
478+
}
479+
480+
void LLVMDisposeOperandBundleDef(LLVMOperandBundleDefRef Bundle) {
481+
delete unwrap<OperandBundleDef>(Bundle);
482+
return;
483+
}
484+
485+
const char *LLVMGetOperandBundleDefTag(LLVMOperandBundleDefRef Bundle, unsigned *Length) {
486+
const OperandBundleDef *S = unwrap<OperandBundleDef>(Bundle);
487+
*Length = S->getTag().size();
488+
return S->getTag().data();
489+
}
490+
491+
unsigned LLVMGetOperandBundleDefNumInputs(LLVMOperandBundleDefRef Bundle) {
492+
return unwrap<OperandBundleDef>(Bundle)->input_size();
493+
}
494+
495+
void LLVMGetOperandBundleDefInputs(LLVMOperandBundleDefRef Bundle, LLVMValueRef *Dest) {
496+
size_t i = 0;
497+
for (auto input: unwrap<OperandBundleDef>(Bundle)->inputs())
498+
Dest[i++] = wrap(input);
499+
}
500+
501+
LLVMValueRef LLVMBuildCallWithOpBundle(LLVMBuilderRef B, LLVMValueRef Fn,
502+
LLVMValueRef *Args, unsigned NumArgs,
503+
LLVMOperandBundleDefRef *Bundles, unsigned NumBundles,
504+
const char *Name) {
505+
Value *V = unwrap(Fn);
506+
FunctionType *FnT =
507+
cast<FunctionType>(cast<PointerType>(V->getType())->getElementType());
508+
509+
SmallVector<OperandBundleDef, 1> BundleArray;
510+
for (auto *Bundle : makeArrayRef(Bundles, NumBundles))
511+
BundleArray.push_back(*unwrap<OperandBundleDef>(Bundle));
512+
513+
return wrap(unwrap(B)->CreateCall(FnT, unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs),
514+
BundleArray, Name));
515+
}

lib/libLLVM_extra.jl

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,68 @@ end
342342
function LLVMDestroyConstant(Const)
343343
ccall((:LLVMDestroyConstant, libLLVMExtra), Cvoid, (LLVMValueRef,), Const)
344344
end
345+
346+
mutable struct LLVMOpaqueOperandBundleUse end
347+
348+
const LLVMOperandBundleUseRef = Ptr{LLVMOpaqueOperandBundleUse}
349+
350+
function LLVMGetNumOperandBundles(Instr)
351+
ccall((:LLVMGetNumOperandBundles, libLLVMExtra), Cuint, (LLVMValueRef,), Instr)
352+
end
353+
354+
function LLVMGetOperandBundle(Val, Index)
355+
ccall((:LLVMGetOperandBundle, libLLVMExtra), LLVMOperandBundleUseRef, (LLVMValueRef, Cuint), Val, Index)
356+
end
357+
358+
function LLVMDisposeOperandBundleUse(Bundle)
359+
ccall((:LLVMDisposeOperandBundleUse, libLLVMExtra), Cvoid, (LLVMOperandBundleUseRef,), Bundle)
360+
end
361+
362+
function LLVMGetOperandBundleUseTagID(Bundle)
363+
ccall((:LLVMGetOperandBundleUseTagID, libLLVMExtra), UInt32, (LLVMOperandBundleUseRef,), Bundle)
364+
end
365+
366+
function LLVMGetOperandBundleUseTagName(Bundle, Length)
367+
ccall((:LLVMGetOperandBundleUseTagName, libLLVMExtra), Cstring, (LLVMOperandBundleUseRef, Ptr{Cuint}), Bundle, Length)
368+
end
369+
370+
function LLVMGetOperandBundleUseNumInputs(Bundle)
371+
ccall((:LLVMGetOperandBundleUseNumInputs, libLLVMExtra), Cuint, (LLVMOperandBundleUseRef,), Bundle)
372+
end
373+
374+
function LLVMGetOperandBundleUseInputs(Bundle, Dest)
375+
ccall((:LLVMGetOperandBundleUseInputs, libLLVMExtra), Cvoid, (LLVMOperandBundleUseRef, Ptr{LLVMValueRef}), Bundle, Dest)
376+
end
377+
378+
mutable struct LLVMOpaqueOperandBundleDef end
379+
380+
const LLVMOperandBundleDefRef = Ptr{LLVMOpaqueOperandBundleDef}
381+
382+
function LLVMOperandBundleDefFromUse(Bundle)
383+
ccall((:LLVMOperandBundleDefFromUse, libLLVMExtra), LLVMOperandBundleDefRef, (LLVMOperandBundleUseRef,), Bundle)
384+
end
385+
386+
function LLVMCreateOperandBundleDef(Tag, Inputs, NumInputs)
387+
ccall((:LLVMCreateOperandBundleDef, libLLVMExtra), LLVMOperandBundleDefRef, (Cstring, Ptr{LLVMValueRef}, Cuint), Tag, Inputs, NumInputs)
388+
end
389+
390+
function LLVMDisposeOperandBundleDef(Bundle)
391+
ccall((:LLVMDisposeOperandBundleDef, libLLVMExtra), Cvoid, (LLVMOperandBundleDefRef,), Bundle)
392+
end
393+
394+
function LLVMGetOperandBundleDefTag(Bundle, Length)
395+
ccall((:LLVMGetOperandBundleDefTag, libLLVMExtra), Cstring, (LLVMOperandBundleDefRef, Ptr{Cuint}), Bundle, Length)
396+
end
397+
398+
function LLVMGetOperandBundleDefNumInputs(Bundle)
399+
ccall((:LLVMGetOperandBundleDefNumInputs, libLLVMExtra), Cuint, (LLVMOperandBundleDefRef,), Bundle)
400+
end
401+
402+
function LLVMGetOperandBundleDefInputs(Bundle, Dest)
403+
ccall((:LLVMGetOperandBundleDefInputs, libLLVMExtra), Cvoid, (LLVMOperandBundleDefRef, Ptr{LLVMValueRef}), Bundle, Dest)
404+
end
405+
406+
function LLVMBuildCallWithOpBundle(B, Fn, Args, NumArgs, Bundles, NumBundles, Name)
407+
ccall((:LLVMBuildCallWithOpBundle, libLLVMExtra), LLVMValueRef, (LLVMBuilderRef, LLVMValueRef, Ptr{LLVMValueRef}, Cuint, Ptr{LLVMOperandBundleDefRef}, Cuint, Cstring), B, Fn, Args, NumArgs, Bundles, NumBundles, Name)
408+
end
409+

src/core/instructions.jl

Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,18 +131,112 @@ end
131131

132132
## call sites and invocations
133133

134+
# TODO: add this to the actual type hierarchy
135+
const CallBase = Union{CallBrInst, CallInst, InvokeInst}
136+
134137
export callconv, callconv!,
135138
istailcall, tailcall!,
136-
called_value
139+
called_value, arguments,
140+
OperandBundleUse, OperandBundleDef, operand_bundles
137141

138-
callconv(inst::Instruction) = API.LLVMGetInstructionCallConv(inst)
139-
callconv!(inst::Instruction, cc) =
142+
callconv(inst::CallBase) = API.LLVMGetInstructionCallConv(inst)
143+
callconv!(inst::CallBase, cc) =
140144
API.LLVMSetInstructionCallConv(inst, cc)
141145

142-
istailcall(inst::Instruction) = convert(Core.Bool, API.LLVMIsTailCall(inst))
143-
tailcall!(inst::Instruction, bool) = API.LLVMSetTailCall(inst, convert(Bool, bool))
146+
istailcall(inst::CallBase) = convert(Core.Bool, API.LLVMIsTailCall(inst))
147+
tailcall!(inst::CallBase, bool) = API.LLVMSetTailCall(inst, convert(Bool, bool))
148+
149+
called_value(inst::CallBase) = Value(API.LLVMGetCalledValue(inst))
150+
151+
function arguments(inst::CallBase)
152+
nargs = API.LLVMGetNumArgOperands(inst)
153+
operands(inst)[1:nargs]
154+
end
155+
156+
# operand bundles
157+
158+
# XXX: these objects are just C structures, whose lifetime isn't tied to LLVM IR structures.
159+
# that means we need to create a copy when passing them to Julia, necessitating disposal.
160+
161+
@checked mutable struct OperandBundleUse
162+
ref::API.LLVMOperandBundleUseRef
163+
end
164+
Base.unsafe_convert(::Type{API.LLVMOperandBundleUseRef}, bundle::OperandBundleUse) =
165+
bundle.ref
166+
167+
struct OperandBundleIterator <: AbstractVector{OperandBundleUse}
168+
inst::Instruction
169+
end
170+
171+
operand_bundles(inst::Instruction) = OperandBundleIterator(inst)
172+
173+
Base.size(iter::OperandBundleIterator) = (API.LLVMGetNumOperandBundles(iter.inst),)
174+
175+
Base.IndexStyle(::OperandBundleIterator) = IndexLinear()
176+
177+
function Base.getindex(iter::OperandBundleIterator, i::Int)
178+
@boundscheck 1 <= i <= length(iter) || throw(BoundsError(iter, i))
179+
bundle = OperandBundleUse(API.LLVMGetOperandBundle(iter.inst, i-1))
180+
finalizer(bundle) do obj
181+
API.LLVMDisposeOperandBundleUse(obj)
182+
end
183+
end
184+
185+
tag_id(bundle::OperandBundleUse) = API.LLVMGetOperandBundleTagID(bundle)
186+
187+
function tag_name(bundle::OperandBundleUse)
188+
len = Ref{Cuint}()
189+
data = API.LLVMGetOperandBundleUseTagName(bundle, len)
190+
unsafe_string(convert(Ptr{Int8}, data), len[])
191+
end
192+
193+
function inputs(bundle::OperandBundleUse)
194+
nvals = API.LLVMGetOperandBundleUseNumInputs(bundle)
195+
vals = Vector{API.LLVMValueRef}(undef, nvals)
196+
API.LLVMGetOperandBundleUseInputs(bundle, vals)
197+
return [Value(val) for val in vals]
198+
end
199+
200+
@checked mutable struct OperandBundleDef
201+
ref::API.LLVMOperandBundleDefRef
202+
end
203+
Base.unsafe_convert(::Type{API.LLVMOperandBundleDefRef}, bundle::OperandBundleDef) =
204+
bundle.ref
205+
206+
function tag_name(bundle::OperandBundleDef)
207+
len = Ref{Cuint}()
208+
data = API.LLVMGetOperandBundleDefTag(bundle, len)
209+
unsafe_string(convert(Ptr{Int8}, data), len[])
210+
end
211+
212+
function OperandBundleDef(bundle_use::OperandBundleUse)
213+
bundle_def = OperandBundleDef(API.LLVMOperandBundleDefFromUse(bundle_use))
214+
finalizer(bundle_def) do obj
215+
API.LLVMDisposeOperandBundleDef(obj)
216+
end
217+
end
218+
219+
function OperandBundleDef(tag::String, inputs::Vector{<:Value}=Value[])
220+
bundle = OperandBundleDef(API.LLVMCreateOperandBundleDef(tag, inputs, length(inputs)))
221+
finalizer(bundle) do obj
222+
API.LLVMDisposeOperandBundleDef(obj)
223+
end
224+
end
225+
226+
function inputs(bundle::OperandBundleDef)
227+
nvals = API.LLVMGetOperandBundleDefNumInputs(bundle)
228+
vals = Vector{API.LLVMValueRef}(undef, nvals)
229+
API.LLVMGetOperandBundleDefInputs(bundle, vals)
230+
return [Value(val) for val in vals]
231+
end
232+
233+
function Base.show(io::IO, bundle::Union{OperandBundleUse,OperandBundleDef})
234+
# mimic how bundles are rendered in LLVM IR
235+
print(io, "\"", tag_name(bundle), "\"(")
236+
join(io, inputs(bundle), ", ")
237+
print(io, ")")
238+
end
144239

145-
called_value(inst::Instruction) = Value(API.LLVMGetCalledValue(inst))
146240

147241

148242
## terminators

src/irbuilder.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,18 @@ select!(builder::Builder, If::Value, Then::Value, Else::Value, Name::String="")
342342
call!(builder::Builder, Fn::Value, Args::Vector{<:Value}=Value[], Name::String="") =
343343
Instruction(API.LLVMBuildCall(builder, Fn, Args, length(Args), Name))
344344

345+
call!(builder::Builder, Fn::Value, Args::Vector{<:Value},
346+
Bundles::Vector{OperandBundleDef}, Name::String="") =
347+
Instruction(API.LLVMBuildCallWithOpBundle(builder, Fn, Args, length(Args), Bundles,
348+
length(Bundles), Name))
349+
350+
# convenience function that performs the OperandBundle(Iterator|Use)->Def conversion
351+
call!(builder::Builder, Fn::Value, Args::Vector{<:Value},
352+
Bundles, Name::String="") =
353+
Instruction(API.LLVMBuildCallWithOpBundle(builder, Fn, Args, length(Args),
354+
OperandBundleDef.(Bundles),
355+
length(Bundles), Name))
356+
345357
va_arg!(builder::Builder, List::Value, Ty::LLVMType, Name::String="") =
346358
Instruction(API.LLVMBuildVAArg(builder, List, Ty, Name))
347359

0 commit comments

Comments
 (0)