-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
[ir] Deprecate FrontendAtomicStmt
#907
Conversation
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.
Great step towards TAI/CHI IR standardization! LGTM except for a few questions..
// replace atomic sub with negative atomic add | ||
if (op_type == AtomicOpType::sub) { | ||
val.set(Expr::make<UnaryOpExpression>(UnaryOpType::neg, val)); | ||
op_type = AtomicOpType::add; | ||
} |
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.
Why? Could you clarify the reason in the comment? I don't understand.. wasn't atomic_sub
slimer than neg+atomic_add
?
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.
I didn't make any change here. Please compare this with the old code (visit(FrontendAtomicStmt*)
)
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 we should ask @yuanming-hu for reason?
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.
I think the reason is simply that the codegen assumes that sub
is converted to add
in the previous passes, see
taichi/taichi/codegen/codegen_llvm.cpp
Lines 947 to 963 in 75335e9
if (stmt->op_type == AtomicOpType::add) { | |
if (is_integral(stmt->val->ret_type.data_type)) { | |
old_value = builder->CreateAtomicRMW( | |
llvm::AtomicRMWInst::BinOp::Add, llvm_val[stmt->dest], | |
llvm_val[stmt->val], llvm::AtomicOrdering::SequentiallyConsistent); | |
} else if (stmt->val->ret_type.data_type == DataType::f32) { | |
old_value = | |
builder->CreateCall(get_runtime_function("atomic_add_f32"), | |
{llvm_val[stmt->dest], llvm_val[stmt->val]}); | |
} else if (stmt->val->ret_type.data_type == DataType::f64) { | |
old_value = | |
builder->CreateCall(get_runtime_function("atomic_add_f64"), | |
{llvm_val[stmt->dest], llvm_val[stmt->val]}); | |
} else { | |
TI_NOT_IMPLEMENTED | |
} | |
} else if (stmt->op_type == AtomicOpType::min) { |
add
, but not sub
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 let's just add handles for sub
? It should have no harm but profitable right? Also metal and gl handles sub too, no reason special for llvm.
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.
I think the current approach is fine. Adding handling forsub
will have to cover all the backends, not just for LLVM. Again, let’s always focus one PR for one thing.
Co-authored-by: 彭于斌 <[email protected]>
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.
Looks good in general, thank you!
void AtomicOpExpression::flatten(FlattenContext *ctx) { | ||
// replace atomic sub with negative atomic add | ||
if (op_type == AtomicOpType::sub) { | ||
val.set(Expr::make<UnaryOpExpression>(UnaryOpType::neg, val)); |
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.
Will this cause an circular reference?
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.
Good point, but nope. If you look into set()
:
Lines 47 to 49 in f5373b1
void set(const Expr &o) { | |
expr = o.expr; | |
} |
It assigns expr
to another std::shared_ptr
. shared_ptr::operator=()
will ref the new object, and deref the old object. https://en.cppreference.com/w/cpp/memory/shared_ptr/operator%3D
current_ast_builder().insert(Stmt::make<FrontendAtomicStmt>( | ||
AtomicOpType::add, *this, -load_if_ptr(o))); | ||
(*this) = Expr::make<AtomicOpExpression>( | ||
AtomicOpType::sub, ptr_if_global(*this), load_if_ptr(o)); |
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.
Why ptr_if_global
appeared? I thought it's already done in L856?
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.
I think it's a bug in the old code. See L131 in the old code for how it handles ::add
, which has ptr_if_global
. Also L856 checks for GlobalPtrExpression, whereas ptr_if_global()
checks for GlobalVariableExpression.
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.
Actually, my feeling is ptr_if_global
should be removed completely in a future PR. We use this wrapper just to allow the syntax like a += 1
for a = ti.var(ti.f32, shape())
(0-D tensors). Enforcing the user to write ``a[None] += 1` will make learning easier since the rule is simpler (though more verbose).
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.
ah ok, then let's do that in a separate PR..
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.
Thanks! LGTM.
current_ast_builder().insert(Stmt::make<FrontendAtomicStmt>( | ||
AtomicOpType::add, *this, -load_if_ptr(o))); | ||
(*this) = Expr::make<AtomicOpExpression>( | ||
AtomicOpType::sub, ptr_if_global(*this), load_if_ptr(o)); |
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.
Actually, my feeling is ptr_if_global
should be removed completely in a future PR. We use this wrapper just to allow the syntax like a += 1
for a = ti.var(ti.f32, shape())
(0-D tensors). Enforcing the user to write ``a[None] += 1` will make learning easier since the rule is simpler (though more verbose).
I added
AtomicOpExpression
back in Jan, where we wanted to maketi.atomic_*()
return the old value. Now I think it's a good time to mergeFrontendAtomicStmt
intoAtomicOpExpression
.Related issue = #689 , #332
[Click here for the format server]