Skip to content

Commit

Permalink
Refactor Expr(:simdloop) to Expr(:loopinfo, ...)
Browse files Browse the repository at this point in the history
- `Expr(:loopinfo, Symbol("julia.simdloop"))` replaces
  `Expr(:simdloop, false)`
- `Expr(:loopinfo, Symbol("julia.simdloop"), Symbol("julia.ivdep"))` replaces
  `Expr(:simdloop, true)`

While currently not directly exposed users can now pass other
[loopinfo](https://llvm.org/docs/LangRef.html#llvm-loop) metadata to
LLVM.
  • Loading branch information
vchuravy committed Mar 12, 2019
1 parent 48e7a35 commit b3ea10a
Show file tree
Hide file tree
Showing 18 changed files with 174 additions and 129 deletions.
2 changes: 1 addition & 1 deletion base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,7 @@ function typeinf_local(frame::InferenceState)
if isa(fname, Slot)
changes = StateUpdate(fname, VarState(Any, false), changes)
end
elseif hd === :inbounds || hd === :meta || hd === :simdloop
elseif hd === :inbounds || hd === :meta || hd === :loopinfo
else
t = abstract_eval(stmt, changes, frame)
t === Bottom && break
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ function stmt_affects_purity(@nospecialize(stmt), ir)
return !(t Bool)
end
if isa(stmt, Expr)
return stmt.head != :simdloop && stmt.head != :enter
return stmt.head != :loopinfo && stmt.head != :enter
end
return true
end
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/ssair/queries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function stmt_effect_free(@nospecialize(stmt), @nospecialize(rt), src, sptypes::
elseif head === :isdefined || head === :the_exception || head === :copyast || head === :inbounds || head === :boundscheck
return true
else
# e.g. :simdloop
# e.g. :loopinfo
return false
end
end
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ end

# Meta expression head, these generally can't be deleted even when they are
# in a dead branch but can be ignored when analyzing uses/liveness.
is_meta_expr_head(head::Symbol) = (head === :inbounds || head === :boundscheck || head === :meta || head === :simdloop)
is_meta_expr_head(head::Symbol) = (head === :inbounds || head === :boundscheck || head === :meta || head === :loopinfo)

sym_isless(a::Symbol, b::Symbol) = ccall(:strcmp, Int32, (Ptr{UInt8}, Ptr{UInt8}), a, b) < 0

Expand Down
4 changes: 2 additions & 2 deletions base/compiler/validation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const VALID_EXPR_HEADS = IdDict{Any,Any}(
:foreigncall => 3:typemax(Int),
:cfunction => 5:5,
:isdefined => 1:1,
:simdloop => 1:1,
:loopinfo => 0:typemax(Int),
:gc_preserve_begin => 0:typemax(Int),
:gc_preserve_end => 0:typemax(Int),
:thunk => 1:1,
Expand Down Expand Up @@ -143,7 +143,7 @@ function validate_code!(errors::Vector{>:InvalidCodeError}, c::CodeInfo, is_top_
head === :inbounds || head === :foreigncall || head === :cfunction ||
head === :const || head === :enter || head === :leave || head == :pop_exception ||
head === :method || head === :global || head === :static_parameter ||
head === :new || head === :splatnew || head === :thunk || head === :simdloop ||
head === :new || head === :splatnew || head === :thunk || head === :loopinfo ||
head === :throw_undef_if_not || head === :unreachable
validate_val!(x)
else
Expand Down
2 changes: 1 addition & 1 deletion base/meta.jl
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,6 @@ end

_instantiate_type_in_env(x, spsig, spvals) = ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), x, spsig, spvals)

is_meta_expr_head(head::Symbol) = (head === :inbounds || head === :boundscheck || head === :meta || head === :simdloop)
is_meta_expr_head(head::Symbol) = (head === :inbounds || head === :boundscheck || head === :meta || head === :loopinfo)

end # module
8 changes: 4 additions & 4 deletions base/simdloop.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ check_body!(x::QuoteNode) = check_body!(x.value)
check_body!(x) = true

# @simd splits a for loop into two loops: an outer scalar loop and
# an inner loop marked with :simdloop. The simd_... functions define
# an inner loop marked with :loopinfo. The simd_... functions define
# the splitting.
# Custom iterators that do not support random access cannot support
# vectorization. In order to be compatible with `@simd` annotated loops,
Expand Down Expand Up @@ -76,7 +76,7 @@ function compile(x, ivdep)
local $var = Base.simd_index($r,$j,$i)
$(x.args[2]) # Body of loop
$i += 1
$(Expr(:simdloop, ivdep)) # Mark loop as SIMD loop
$(Expr(:loopinfo, Symbol("julia.simdloop"), ivdep)) # Mark loop as SIMD loop
end
end
end
Expand Down Expand Up @@ -125,12 +125,12 @@ either case, your inner loop should have the following properties to allow vecto
* No iteration ever waits on a previous iteration to make forward progress.
"""
macro simd(forloop)
esc(compile(forloop, false))
esc(compile(forloop, nothing))
end

macro simd(ivdep, forloop)
if ivdep == :ivdep
esc(compile(forloop, true))
esc(compile(forloop, Symbol("julia.ivdep")))
else
throw(SimdError("Only ivdep is valid as the first argument to @simd"))
end
Expand Down
5 changes: 3 additions & 2 deletions doc/src/devdocs/ast.md
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,10 @@ These symbols appear in the `head` field of [`Expr`](@ref)s in lowered form.
Has the value `false` if inlined into a section of code marked with `@inbounds`,
otherwise has the value `true`.

* `simdloop`
* `loopinfo`

Marks the end of the inner loop of a `@simd` expression.
Marks the end of the a loop. Contains metadata that is passed to `LowerSimdLoop` to either mark
the inner loop of `@simd` expression, or to propagate information to LLVM loop passes.

* `copyast`

Expand Down
4 changes: 2 additions & 2 deletions src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jl_sym_t *global_sym; jl_sym_t *list_sym;
jl_sym_t *dot_sym; jl_sym_t *newvar_sym;
jl_sym_t *boundscheck_sym; jl_sym_t *inbounds_sym;
jl_sym_t *copyast_sym; jl_sym_t *cfunction_sym;
jl_sym_t *pure_sym; jl_sym_t *simdloop_sym;
jl_sym_t *pure_sym; jl_sym_t *loopinfo_sym;
jl_sym_t *meta_sym; jl_sym_t *inert_sym;
jl_sym_t *polly_sym; jl_sym_t *unused_sym;
jl_sym_t *static_parameter_sym; jl_sym_t *inline_sym;
Expand Down Expand Up @@ -341,7 +341,7 @@ void jl_init_frontend(void)
inbounds_sym = jl_symbol("inbounds");
newvar_sym = jl_symbol("newvar");
copyast_sym = jl_symbol("copyast");
simdloop_sym = jl_symbol("simdloop");
loopinfo_sym = jl_symbol("loopinfo");
pure_sym = jl_symbol("pure");
meta_sym = jl_symbol("meta");
list_sym = jl_symbol("list");
Expand Down
66 changes: 42 additions & 24 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,6 @@
#include <llvm/ExecutionEngine/ExecutionEngine.h>

using namespace llvm;
namespace llvm {
extern bool annotateSimdLoop(BasicBlock *latch);
}

#if defined(_OS_WINDOWS_) && !defined(NOMINMAX)
#define NOMINMAX
Expand Down Expand Up @@ -296,8 +293,7 @@ static Function *jlegal_func;
static Function *jl_alloc_obj_func;
static Function *jl_newbits_func;
static Function *jl_typeof_func;
static Function *jl_simdloop_marker_func;
static Function *jl_simdivdep_marker_func;
static Function *jl_loopinfo_marker_func;
static Function *jl_write_barrier_func;
static Function *jlisa_func;
static Function *jlsubtype_func;
Expand Down Expand Up @@ -4100,14 +4096,43 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval)
ctx.builder.CreateCall(prepare_call(jlcopyast_func),
maybe_decay_untracked(boxed(ctx, ast))), true, jl_expr_type);
}
else if (head == simdloop_sym) {
jl_value_t *ivdep = args[0];
assert(jl_expr_nargs(ex) == 1 && jl_is_bool(ivdep));
if (ivdep == jl_false) {
ctx.builder.CreateCall(prepare_call(jl_simdloop_marker_func));
} else {
ctx.builder.CreateCall(prepare_call(jl_simdivdep_marker_func));
else if (head == loopinfo_sym) {
// parse Expr(:loopinfo, "julia.simdloop", ("llvm.loop.vectorize.width", 4))
SmallVector<Metadata *, 8> MDs;
for (int i = 0, ie = jl_expr_nargs(ex); i < ie; ++i) {
jl_value_t *arg = args[i];
Metadata *MD;
if (arg == jl_nothing)
continue;
if (jl_is_symbol(arg)) {
MD = MDString::get(jl_LLVMContext, jl_symbol_name((jl_sym_t*)arg));
} else if (jl_is_tuple(arg)) {
// TODO: are there loopinfo with more than one field?
if (jl_nfields(arg) != 2)
jl_error("loopinfo: only accept 2-arg tuple");
jl_value_t* name = jl_fieldref(arg, 0);
jl_value_t* value = jl_fieldref(arg, 1);
if (!jl_is_symbol(name))
jl_error("loopinfo: name needs to be a symbol");
Metadata *MDVal;
if(jl_is_bool(value))
MDVal = ConstantAsMetadata::get(ConstantInt::get(T_int1, jl_unbox_bool(value)));
if(jl_is_long(value))
MDVal = ConstantAsMetadata::get(ConstantInt::get(T_int64, jl_unbox_long(value)));
if(!MDVal)
jl_error("loopinfo: value can only be a bool or a long");
MD = MDNode::get(jl_LLVMContext,
{ MDString::get(jl_LLVMContext, jl_symbol_name((jl_sym_t*)name)), MDVal });
}
if (MD)
MDs.push_back(MD);
else
jl_error("loopinfo: argument needs to be either a symbol or a tuple of type (Symbol, Union{Int, Bool}");
}

MDNode* MD = MDNode::get(jl_LLVMContext, MDs);
CallInst *I = ctx.builder.CreateCall(prepare_call(jl_loopinfo_marker_func));
I->setMetadata("julia.loopinfo", MD);
return jl_cgval_t();
}
else if (head == goto_ifnot_sym) {
Expand Down Expand Up @@ -7356,19 +7381,12 @@ static void init_julia_llvm_env(Module *m)
add_return_attr(jl_newbits_func, Attribute::NonNull);
add_named_global(jl_newbits_func, (void*)jl_new_bits);

jl_simdloop_marker_func = Function::Create(FunctionType::get(T_void, {}, false),
Function::ExternalLinkage,
"julia.simdloop_marker");
jl_simdloop_marker_func->addFnAttr(Attribute::NoUnwind);
jl_simdloop_marker_func->addFnAttr(Attribute::NoRecurse);
jl_simdloop_marker_func->addFnAttr(Attribute::InaccessibleMemOnly);

jl_simdivdep_marker_func = Function::Create(FunctionType::get(T_void, {}, false),
jl_loopinfo_marker_func = Function::Create(FunctionType::get(T_void, {}, false),
Function::ExternalLinkage,
"julia.simdivdep_marker");
jl_simdivdep_marker_func->addFnAttr(Attribute::NoUnwind);
jl_simdivdep_marker_func->addFnAttr(Attribute::NoRecurse);
jl_simdivdep_marker_func->addFnAttr(Attribute::InaccessibleMemOnly);
"julia.loopinfo_marker");
jl_loopinfo_marker_func->addFnAttr(Attribute::NoUnwind);
jl_loopinfo_marker_func->addFnAttr(Attribute::NoRecurse);
jl_loopinfo_marker_func->addFnAttr(Attribute::InaccessibleMemOnly);

jl_typeof_func = Function::Create(FunctionType::get(T_prjlvalue, {T_prjlvalue}, false),
Function::ExternalLinkage,
Expand Down
2 changes: 1 addition & 1 deletion src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ SECT_INTERP static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s)
else if (head == boundscheck_sym) {
return jl_true;
}
else if (head == meta_sym || head == inbounds_sym || head == simdloop_sym) {
else if (head == meta_sym || head == inbounds_sym || head == loopinfo_sym) {
return jl_nothing;
}
else if (head == gc_preserve_begin_sym || head == gc_preserve_end_sym) {
Expand Down
6 changes: 3 additions & 3 deletions src/jitlayers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
PM->add(createGCInvariantVerifierPass(false));
PM->add(createLateLowerGCFramePass());
PM->add(createLowerPTLSPass(dump_native));
PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "simdloop" as LLVM parallel loop
}
PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "loopinfo" as LLVM parallel loop
if (dump_native)
PM->add(createMultiVersioningPass());
return;
Expand Down Expand Up @@ -180,7 +180,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
PM->add(polly::createCodegenCleanupPass());
#endif
// LoopRotate strips metadata from terminator, so run LowerSIMD afterwards
PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "simdloop" as LLVM parallel loop
PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "loopinfo" as LLVM parallel loop
PM->add(createLICMPass()); // Hoist loop invariants
PM->add(createLoopUnswitchPass()); // Unswitch loops.
// Subsequent passes not stripping metadata from terminator
Expand Down Expand Up @@ -236,8 +236,8 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
PM->add(createLowerPTLSPass(dump_native));
// Clean up write barrier and ptls lowering
PM->add(createCFGSimplificationPass());
PM->add(createCombineMulAddPass());
}
PM->add(createCombineMulAddPass());
}

extern "C" JL_DLLEXPORT
Expand Down
4 changes: 2 additions & 2 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -2951,7 +2951,7 @@ f(x) = yt(x)

(define lambda-opt-ignored-exprs
(Set '(quote top core line inert local local-def unnecessary copyast
meta inbounds boundscheck simdloop decl aliasscope popaliasscope
meta inbounds boundscheck loopinfo decl aliasscope popaliasscope
struct_type abstract_type primitive_type thunk with-static-parameters
implicit-global global globalref outerref const-if-global
const null ssavalue isdefined toplevel module lambda error
Expand Down Expand Up @@ -3971,7 +3971,7 @@ f(x) = yt(x)
s))

;; metadata expressions
((line meta inbounds simdloop gc_preserve_end aliasscope popaliasscope)
((line meta inbounds loopinfo gc_preserve_end aliasscope popaliasscope)
(let ((have-ret? (and (pair? code) (pair? (car code)) (eq? (caar code) 'return))))
(cond ((eq? (car e) 'line)
(set! current-loc e)
Expand Down
2 changes: 1 addition & 1 deletion src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ extern jl_sym_t *dot_sym; extern jl_sym_t *newvar_sym;
extern jl_sym_t *boundscheck_sym; extern jl_sym_t *inbounds_sym;
extern jl_sym_t *aliasscope_sym; extern jl_sym_t *popaliasscope_sym;
extern jl_sym_t *copyast_sym; extern jl_sym_t *cfunction_sym;
extern jl_sym_t *pure_sym; extern jl_sym_t *simdloop_sym;
extern jl_sym_t *pure_sym; extern jl_sym_t *loopinfo_sym;
extern jl_sym_t *meta_sym; extern jl_sym_t *inert_sym;
extern jl_sym_t *polly_sym; extern jl_sym_t *unused_sym;
extern jl_sym_t *static_parameter_sym; extern jl_sym_t *inline_sym;
Expand Down
Loading

0 comments on commit b3ea10a

Please sign in to comment.