Skip to content

Commit 3eced2e

Browse files
committed
Add support for inspecting and creating operand bundles.
1 parent 9155a8c commit 3eced2e

File tree

7 files changed

+380
-2
lines changed

7 files changed

+380
-2
lines changed

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: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,12 @@ end
131131

132132
## call sites and invocations
133133

134+
# TODO: restrict these to CallBase instructions
135+
134136
export callconv, callconv!,
135137
istailcall, tailcall!,
136-
called_value
138+
called_value, num_arg_operands,
139+
OperandBundleUse, OperandBundleDef, operand_bundles
137140

138141
callconv(inst::Instruction) = API.LLVMGetInstructionCallConv(inst)
139142
callconv!(inst::Instruction, cc) =
@@ -144,6 +147,93 @@ tailcall!(inst::Instruction, bool) = API.LLVMSetTailCall(inst, convert(Bool, boo
144147

145148
called_value(inst::Instruction) = Value(API.LLVMGetCalledValue(inst))
146149

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

148238
## terminators
149239

src/irbuilder.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,11 @@ 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+
345350
va_arg!(builder::Builder, List::Value, Ty::LLVMType, Name::String="") =
346351
Instruction(API.LLVMBuildVAArg(builder, List, Ty, Name))
347352

0 commit comments

Comments
 (0)