-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rebase of julia effects to LLVM #50188
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -1807,6 +1807,53 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, const | |||
static Value *literal_pointer_val(jl_codectx_t &ctx, jl_value_t *p); | ||||
static unsigned julia_alignment(jl_value_t *jt); | ||||
|
||||
static AttributeList get_attrs_ipoeffects(jl_codectx_t &ctx, std::pair<bool,uint32_t> effect, bool is_decl, bool has_ptr_arg) | ||||
{ | ||||
auto &context = ctx.builder.getContext(); | ||||
if (!effect.first) | ||||
return AttributeList(); | ||||
uint32_t effects = effect.second; | ||||
uint8_t consistent = (effects >> 0) & 0x07; | ||||
uint8_t effect_free = (effects >> 3) & 0x03; | ||||
bool nothrow = (effects >> 5) & 0x01; | ||||
bool terminates = (effects >> 6) & 0x01; | ||||
bool notaskstate = (effects >> 7) & 0x01; | ||||
uint8_t inaccessiblememonly = (effects >> 8) & 0x03; | ||||
bool nonoverlayed = (effects >> 10) & 0x01; | ||||
bool noinbounds = (effects >> 11) & 0x01; | ||||
AttrBuilder attr(context); | ||||
|
||||
if (consistent == 0) { | ||||
} | ||||
if (effect_free == 0) { | ||||
// if (!has_ptr_arg) | ||||
// attr.addAttribute(Attribute::ReadOnly); //Not legal because of the ptls | ||||
} | ||||
if (nothrow == 1) { | ||||
attr.addAttribute(Attribute::NoUnwind); | ||||
} | ||||
if (terminates == 1){ | ||||
attr.addAttribute(Attribute::WillReturn); | ||||
} | ||||
if (inaccessiblememonly == 0) { | ||||
attr.addAttribute(Attribute::InaccessibleMemOrArgMemOnly); // Can't be inaccesiblememonly because of the ptls | ||||
} else if (inaccessiblememonly == 2){ | ||||
attr.addAttribute(Attribute::InaccessibleMemOrArgMemOnly); | ||||
} | ||||
if (notaskstate == 1) { | ||||
} | ||||
if (nonoverlayed == 1) { | ||||
} | ||||
if (noinbounds == 1) { | ||||
} | ||||
if (is_decl && consistent == 0 && effect_free == 0 && nothrow == 1 && terminates == 1 && has_ptr_arg == false){ | ||||
attr.addAttribute(Attribute::Speculatable); // This might not be legal because it assumes pointers can be null | ||||
} | ||||
if (ctx.emission_context.debug_level >= 2) | ||||
attr.addAttribute(std::to_string(effects)); | ||||
return AttributeList::get(context,AttributeSet::get(context, attr), AttributeSet(), None); | ||||
} | ||||
|
||||
static GlobalVariable *prepare_global_in(Module *M, JuliaVariable *G) | ||||
{ | ||||
return G->realize(M); | ||||
|
@@ -4246,7 +4293,7 @@ static CallInst *emit_jlcall(jl_codectx_t &ctx, JuliaFunction<> *theFptr, Value | |||
} | ||||
|
||||
static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_closure, jl_value_t *specTypes, jl_value_t *jlretty, llvm::Value *callee, StringRef specFunctionObject, jl_code_instance_t *fromexternal, | ||||
const jl_cgval_t *argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty) | ||||
const jl_cgval_t *argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty, std::pair<bool,uint32_t> effects = {false,0}) | ||||
{ | ||||
++EmittedSpecfunCalls; | ||||
// emit specialized call site | ||||
|
@@ -4290,6 +4337,7 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos | |||
argvals[idx] = ctx.pgcstack; | ||||
idx++; | ||||
} | ||||
bool has_ptr_arg = false; | ||||
for (size_t i = 0; i < nargs; i++) { | ||||
jl_value_t *jt = jl_nth_slot_type(specTypes, i); | ||||
// n.b.: specTypes is required to be a datatype by construction for specsig | ||||
|
@@ -4333,10 +4381,16 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos | |||
argvals[idx] = val; | ||||
} | ||||
} | ||||
if(argvals[idx]->getType()->isPointerTy()) | ||||
has_ptr_arg = true; | ||||
idx++; | ||||
} | ||||
assert(idx == nfargs); | ||||
Value *TheCallee = returninfo.decl.getCallee(); | ||||
auto attrs = AttributeList(); | ||||
if (auto fun = dyn_cast<Function>(TheCallee)){ | ||||
attrs = fun->getAttributes(); | ||||
} | ||||
if (fromexternal) { | ||||
std::string namep("p"); | ||||
namep += cast<Function>(returninfo.decl.getCallee())->getName(); | ||||
|
@@ -4353,7 +4407,12 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos | |||
setName(ctx.emission_context, TheCallee, namep); | ||||
} | ||||
CallInst *call = ctx.builder.CreateCall(cft, TheCallee, argvals); | ||||
call->setAttributes(returninfo.attrs); | ||||
if (auto fun = dyn_cast<Function>(TheCallee)){ | ||||
fun->setAttributes(AttributeList::get(ctx.builder.getContext(), {get_attrs_ipoeffects(ctx, effects, true, has_ptr_arg), returninfo.attrs, attrs})); | ||||
call->setAttributes(returninfo.attrs); | ||||
} | ||||
else | ||||
call->setAttributes(AttributeList::get(ctx.builder.getContext(), {get_attrs_ipoeffects(ctx, effects, false, has_ptr_arg), returninfo.attrs})); | ||||
if (gcstack_arg) | ||||
call->setCallingConv(CallingConv::Swift); | ||||
|
||||
|
@@ -4395,11 +4454,11 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos | |||
} | ||||
|
||||
static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_method_instance_t *mi, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal, | ||||
const jl_cgval_t *argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty) | ||||
const jl_cgval_t *argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty, std::pair<bool,uint32_t> effects = {false,0}) | ||||
{ | ||||
bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; | ||||
return emit_call_specfun_other(ctx, is_opaque_closure, mi->specTypes, jlretty, NULL, | ||||
specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty); | ||||
specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty, effects); | ||||
} | ||||
|
||||
static jl_cgval_t emit_call_specfun_boxed(jl_codectx_t &ctx, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal, | ||||
|
@@ -4530,7 +4589,7 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, const | |||
jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed; | ||||
unsigned return_roots = 0; | ||||
if (specsig) | ||||
result = emit_call_specfun_other(ctx, mi, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt); | ||||
result = emit_call_specfun_other(ctx, mi, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, {true,codeinst->ipo_purity_bits}); | ||||
else | ||||
result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt); | ||||
handled = true; | ||||
|
@@ -7075,15 +7134,21 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value | |||
else { | ||||
rt = ctx.types().T_prjlvalue; | ||||
} | ||||
const DataLayout &DL = M->getDataLayout(); | ||||
|
||||
SmallVector<AttributeSet, 8> attrs; // function declaration attributes | ||||
if (props.cc == jl_returninfo_t::SRet) { | ||||
assert(srt); | ||||
TypeSize sz = DL.getTypeAllocSize(srt); | ||||
Align al = DL.getPrefTypeAlign(srt); | ||||
AttrBuilder param(ctx.builder.getContext()); | ||||
param.addStructRetAttr(srt); | ||||
param.addAttribute(Attribute::NonNull); | ||||
param.addAttribute(Attribute::NoAlias); | ||||
param.addAttribute(Attribute::NoCapture); | ||||
param.addAttribute(Attribute::NoUndef); | ||||
param.addDereferenceableAttr(sz); | ||||
param.addAlignmentAttr(al); | ||||
attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); | ||||
assert(fsig.size() == 1); | ||||
} | ||||
|
@@ -7092,6 +7157,9 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value | |||
param.addAttribute(Attribute::NoAlias); | ||||
param.addAttribute(Attribute::NoCapture); | ||||
param.addAttribute(Attribute::NoUndef); | ||||
param.addAttribute(Attribute::NonNull); | ||||
param.addDereferenceableAttr(props.union_bytes); | ||||
param.addAlignmentAttr(props.union_align); | ||||
Comment on lines
+7161
to
+7162
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we actually ensure this when making this sret alloca? Normally this is the upper bounds that are permitted to be assumed, not the actual values at runtime, but this might be a special case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This what we do when we build the function in Line 7806 in 8b8da91
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, fair. That is the only place it matters too. Elsewhere it just adds a little bit of extra overhead to the function declaration to track some extraneous attributes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't it potenially give more information with how much memory an sret a function has ,i t's likely that the information is there on the pointer now but with opaque pointers it might not be? |
||||
attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); | ||||
assert(fsig.size() == 1); | ||||
} | ||||
|
@@ -7101,6 +7169,10 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value | |||
param.addAttribute(Attribute::NoAlias); | ||||
param.addAttribute(Attribute::NoCapture); | ||||
param.addAttribute(Attribute::NoUndef); | ||||
param.addAttribute(Attribute::NonNull); | ||||
size_t size = props.return_roots * sizeof(jl_value_t*); | ||||
param.addDereferenceableAttr(size); | ||||
param.addAlignmentAttr(Align(sizeof(jl_value_t*))); | ||||
attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); | ||||
fsig.push_back(get_returnroots_type(ctx, props.return_roots)->getPointerTo(0)); | ||||
argnames.push_back("return_roots"); | ||||
|
@@ -7141,6 +7213,7 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value | |||
if (ty->isAggregateType()) { // aggregate types are passed by pointer | ||||
param.addAttribute(Attribute::NoCapture); | ||||
param.addAttribute(Attribute::ReadOnly); | ||||
maybe_mark_argument_dereferenceable(param, jt); | ||||
ty = PointerType::get(ty, AddressSpace::Derived); | ||||
} | ||||
else if (isboxed && jl_is_immutable_datatype(jt)) { | ||||
|
@@ -7151,6 +7224,8 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value | |||
Attribute::AttrKind attr = issigned ? Attribute::SExt : Attribute::ZExt; | ||||
param.addAttribute(attr); | ||||
} | ||||
if (isboxed) | ||||
maybe_mark_argument_dereferenceable(param, jt); | ||||
attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); | ||||
fsig.push_back(ty); | ||||
if (used_arguments) | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that read only task state or task state at all?
I.e. should we verify this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, from the docs