shader: Always initialize up reference in structure control flow

Fixes ubsan issue.
This commit is contained in:
ReinUsesLisp 2021-05-29 19:58:36 -03:00 committed by ameerj
parent 99f2c31b64
commit 329dea217d

View file

@ -101,22 +101,24 @@ struct Statement : ListBaseHook {
: children{std::move(children_)}, cond{cond_}, up{up_}, type{StatementType::Loop} {} : children{std::move(children_)}, cond{cond_}, up{up_}, type{StatementType::Loop} {}
Statement(Break, Statement* cond_, Statement* up_) Statement(Break, Statement* cond_, Statement* up_)
: cond{cond_}, up{up_}, type{StatementType::Break} {} : cond{cond_}, up{up_}, type{StatementType::Break} {}
Statement(Return) : type{StatementType::Return} {} Statement(Return, Statement* up_) : up{up_}, type{StatementType::Return} {}
Statement(Kill) : type{StatementType::Kill} {} Statement(Kill, Statement* up_) : up{up_}, type{StatementType::Kill} {}
Statement(Unreachable) : type{StatementType::Unreachable} {} Statement(Unreachable, Statement* up_) : up{up_}, type{StatementType::Unreachable} {}
Statement(FunctionTag) : children{}, type{StatementType::Function} {} Statement(FunctionTag) : children{}, type{StatementType::Function} {}
Statement(Identity, IR::Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {} Statement(Identity, IR::Condition cond_, Statement* up_)
Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {} : guest_cond{cond_}, up{up_}, type{StatementType::Identity} {}
Statement(Or, Statement* op_a_, Statement* op_b_) Statement(Not, Statement* op_, Statement* up_) : op{op_}, up{up_}, type{StatementType::Not} {}
: op_a{op_a_}, op_b{op_b_}, type{StatementType::Or} {} Statement(Or, Statement* op_a_, Statement* op_b_, Statement* up_)
: op_a{op_a_}, op_b{op_b_}, up{up_}, type{StatementType::Or} {}
Statement(SetVariable, u32 id_, Statement* op_, Statement* up_) Statement(SetVariable, u32 id_, Statement* op_, Statement* up_)
: op{op_}, id{id_}, up{up_}, type{StatementType::SetVariable} {} : op{op_}, id{id_}, up{up_}, type{StatementType::SetVariable} {}
Statement(SetIndirectBranchVariable, IR::Reg branch_reg_, s32 branch_offset_) Statement(SetIndirectBranchVariable, IR::Reg branch_reg_, s32 branch_offset_, Statement* up_)
: branch_offset{branch_offset_}, : branch_offset{branch_offset_},
branch_reg{branch_reg_}, type{StatementType::SetIndirectBranchVariable} {} branch_reg{branch_reg_}, up{up_}, type{StatementType::SetIndirectBranchVariable} {}
Statement(Variable, u32 id_) : id{id_}, type{StatementType::Variable} {} Statement(Variable, u32 id_, Statement* up_)
Statement(IndirectBranchCond, u32 location_) : id{id_}, up{up_}, type{StatementType::Variable} {}
: location{location_}, type{StatementType::IndirectBranchCond} {} Statement(IndirectBranchCond, u32 location_, Statement* up_)
: location{location_}, up{up_}, type{StatementType::IndirectBranchCond} {}
~Statement() { ~Statement() {
if (HasChildren(type)) { if (HasChildren(type)) {
@ -385,7 +387,7 @@ private:
void BuildTree(Flow::CFG& cfg, Flow::Function& function, u32& label_id, void BuildTree(Flow::CFG& cfg, Flow::Function& function, u32& label_id,
std::vector<Node>& gotos, Node function_insert_point, std::vector<Node>& gotos, Node function_insert_point,
std::optional<Node> return_label) { std::optional<Node> return_label) {
Statement* const false_stmt{pool.Create(Identity{}, IR::Condition{false})}; Statement* const false_stmt{pool.Create(Identity{}, IR::Condition{false}, &root_stmt)};
Tree& root{root_stmt.children}; Tree& root{root_stmt.children};
std::unordered_map<Flow::Block*, Node> local_labels; std::unordered_map<Flow::Block*, Node> local_labels;
local_labels.reserve(function.blocks.size()); local_labels.reserve(function.blocks.size());
@ -411,7 +413,8 @@ private:
switch (block.end_class) { switch (block.end_class) {
case Flow::EndClass::Branch: { case Flow::EndClass::Branch: {
Statement* const always_cond{pool.Create(Identity{}, IR::Condition{true})}; Statement* const always_cond{
pool.Create(Identity{}, IR::Condition{true}, &root_stmt)};
if (block.cond == IR::Condition{true}) { if (block.cond == IR::Condition{true}) {
const Node true_label{local_labels.at(block.branch_true)}; const Node true_label{local_labels.at(block.branch_true)};
gotos.push_back( gotos.push_back(
@ -423,7 +426,7 @@ private:
} else { } else {
const Node true_label{local_labels.at(block.branch_true)}; const Node true_label{local_labels.at(block.branch_true)};
const Node false_label{local_labels.at(block.branch_false)}; const Node false_label{local_labels.at(block.branch_false)};
Statement* const true_cond{pool.Create(Identity{}, block.cond)}; Statement* const true_cond{pool.Create(Identity{}, block.cond, &root_stmt)};
gotos.push_back( gotos.push_back(
root.insert(ip, *pool.Create(Goto{}, true_cond, true_label, &root_stmt))); root.insert(ip, *pool.Create(Goto{}, true_cond, true_label, &root_stmt)));
gotos.push_back(root.insert( gotos.push_back(root.insert(
@ -433,14 +436,15 @@ private:
} }
case Flow::EndClass::IndirectBranch: case Flow::EndClass::IndirectBranch:
root.insert(ip, *pool.Create(SetIndirectBranchVariable{}, block.branch_reg, root.insert(ip, *pool.Create(SetIndirectBranchVariable{}, block.branch_reg,
block.branch_offset)); block.branch_offset, &root_stmt));
for (const Flow::IndirectBranch& indirect : block.indirect_branches) { for (const Flow::IndirectBranch& indirect : block.indirect_branches) {
const Node indirect_label{local_labels.at(indirect.block)}; const Node indirect_label{local_labels.at(indirect.block)};
Statement* cond{pool.Create(IndirectBranchCond{}, indirect.address)}; Statement* cond{
pool.Create(IndirectBranchCond{}, indirect.address, &root_stmt)};
Statement* goto_stmt{pool.Create(Goto{}, cond, indirect_label, &root_stmt)}; Statement* goto_stmt{pool.Create(Goto{}, cond, indirect_label, &root_stmt)};
gotos.push_back(root.insert(ip, *goto_stmt)); gotos.push_back(root.insert(ip, *goto_stmt));
} }
root.insert(ip, *pool.Create(Unreachable{})); root.insert(ip, *pool.Create(Unreachable{}, &root_stmt));
break; break;
case Flow::EndClass::Call: { case Flow::EndClass::Call: {
Flow::Function& call{cfg.Functions()[block.function_call]}; Flow::Function& call{cfg.Functions()[block.function_call]};
@ -449,16 +453,16 @@ private:
break; break;
} }
case Flow::EndClass::Exit: case Flow::EndClass::Exit:
root.insert(ip, *pool.Create(Return{})); root.insert(ip, *pool.Create(Return{}, &root_stmt));
break; break;
case Flow::EndClass::Return: { case Flow::EndClass::Return: {
Statement* const always_cond{pool.Create(Identity{}, block.cond)}; Statement* const always_cond{pool.Create(Identity{}, block.cond, &root_stmt)};
auto goto_stmt{pool.Create(Goto{}, always_cond, return_label.value(), &root_stmt)}; auto goto_stmt{pool.Create(Goto{}, always_cond, return_label.value(), &root_stmt)};
gotos.push_back(root.insert(ip, *goto_stmt)); gotos.push_back(root.insert(ip, *goto_stmt));
break; break;
} }
case Flow::EndClass::Kill: case Flow::EndClass::Kill:
root.insert(ip, *pool.Create(Kill{})); root.insert(ip, *pool.Create(Kill{}, &root_stmt));
break; break;
} }
} }
@ -474,7 +478,7 @@ private:
Tree& body{goto_stmt->up->children}; Tree& body{goto_stmt->up->children};
Tree if_body; Tree if_body;
if_body.splice(if_body.begin(), body, std::next(goto_stmt), label_stmt); if_body.splice(if_body.begin(), body, std::next(goto_stmt), label_stmt);
Statement* const cond{pool.Create(Not{}, goto_stmt->cond)}; Statement* const cond{pool.Create(Not{}, goto_stmt->cond, &root_stmt)};
Statement* const if_stmt{pool.Create(If{}, cond, std::move(if_body), goto_stmt->up)}; Statement* const if_stmt{pool.Create(If{}, cond, std::move(if_body), goto_stmt->up)};
UpdateTreeUp(if_stmt); UpdateTreeUp(if_stmt);
body.insert(goto_stmt, *if_stmt); body.insert(goto_stmt, *if_stmt);
@ -516,8 +520,8 @@ private:
Tree if_body; Tree if_body;
if_body.splice(if_body.begin(), body, std::next(goto_stmt), label_nested_stmt); if_body.splice(if_body.begin(), body, std::next(goto_stmt), label_nested_stmt);
Statement* const variable{pool.Create(Variable{}, label_id)}; Statement* const variable{pool.Create(Variable{}, label_id, &root_stmt)};
Statement* const neg_var{pool.Create(Not{}, variable)}; Statement* const neg_var{pool.Create(Not{}, variable, &root_stmt)};
if (!if_body.empty()) { if (!if_body.empty()) {
Statement* const if_stmt{pool.Create(If{}, neg_var, std::move(if_body), parent)}; Statement* const if_stmt{pool.Create(If{}, neg_var, std::move(if_body), parent)};
UpdateTreeUp(if_stmt); UpdateTreeUp(if_stmt);
@ -528,7 +532,8 @@ private:
switch (label_nested_stmt->type) { switch (label_nested_stmt->type) {
case StatementType::If: case StatementType::If:
// Update nested if condition // Update nested if condition
label_nested_stmt->cond = pool.Create(Or{}, variable, label_nested_stmt->cond); label_nested_stmt->cond =
pool.Create(Or{}, variable, label_nested_stmt->cond, &root_stmt);
break; break;
case StatementType::Loop: case StatementType::Loop:
break; break;
@ -550,7 +555,7 @@ private:
Tree loop_body; Tree loop_body;
loop_body.splice(loop_body.begin(), body, label_nested_stmt, goto_stmt); loop_body.splice(loop_body.begin(), body, label_nested_stmt, goto_stmt);
SanitizeNoBreaks(loop_body); SanitizeNoBreaks(loop_body);
Statement* const variable{pool.Create(Variable{}, label_id)}; Statement* const variable{pool.Create(Variable{}, label_id, &root_stmt)};
Statement* const loop_stmt{pool.Create(Loop{}, variable, std::move(loop_body), parent)}; Statement* const loop_stmt{pool.Create(Loop{}, variable, std::move(loop_body), parent)};
UpdateTreeUp(loop_stmt); UpdateTreeUp(loop_stmt);
body.insert(goto_stmt, *loop_stmt); body.insert(goto_stmt, *loop_stmt);
@ -577,15 +582,15 @@ private:
Tree if_body; Tree if_body;
if_body.splice(if_body.begin(), body, std::next(goto_stmt), body.end()); if_body.splice(if_body.begin(), body, std::next(goto_stmt), body.end());
if_body.pop_front(); if_body.pop_front();
Statement* const cond{pool.Create(Variable{}, label_id)}; Statement* const cond{pool.Create(Variable{}, label_id, &root_stmt)};
Statement* const neg_cond{pool.Create(Not{}, cond)}; Statement* const neg_cond{pool.Create(Not{}, cond, &root_stmt)};
Statement* const if_stmt{pool.Create(If{}, neg_cond, std::move(if_body), &*parent)}; Statement* const if_stmt{pool.Create(If{}, neg_cond, std::move(if_body), &*parent)};
UpdateTreeUp(if_stmt); UpdateTreeUp(if_stmt);
body.insert(goto_stmt, *if_stmt); body.insert(goto_stmt, *if_stmt);
body.erase(goto_stmt); body.erase(goto_stmt);
Statement* const new_cond{pool.Create(Variable{}, label_id)}; Statement* const new_cond{pool.Create(Variable{}, label_id, &root_stmt)};
Statement* const new_goto{pool.Create(Goto{}, new_cond, goto_stmt->label, parent->up)}; Statement* const new_goto{pool.Create(Goto{}, new_cond, goto_stmt->label, parent->up)};
Tree& parent_tree{parent->up->children}; Tree& parent_tree{parent->up->children};
return parent_tree.insert(std::next(parent), *new_goto); return parent_tree.insert(std::next(parent), *new_goto);
@ -597,14 +602,14 @@ private:
const u32 label_id{goto_stmt->label->id}; const u32 label_id{goto_stmt->label->id};
Statement* const goto_cond{goto_stmt->cond}; Statement* const goto_cond{goto_stmt->cond};
Statement* const set_goto_var{pool.Create(SetVariable{}, label_id, goto_cond, parent)}; Statement* const set_goto_var{pool.Create(SetVariable{}, label_id, goto_cond, parent)};
Statement* const cond{pool.Create(Variable{}, label_id)}; Statement* const cond{pool.Create(Variable{}, label_id, &root_stmt)};
Statement* const break_stmt{pool.Create(Break{}, cond, parent)}; Statement* const break_stmt{pool.Create(Break{}, cond, parent)};
body.insert(goto_stmt, *set_goto_var); body.insert(goto_stmt, *set_goto_var);
body.insert(goto_stmt, *break_stmt); body.insert(goto_stmt, *break_stmt);
body.erase(goto_stmt); body.erase(goto_stmt);
const Node loop{Tree::s_iterator_to(*goto_stmt->up)}; const Node loop{Tree::s_iterator_to(*goto_stmt->up)};
Statement* const new_goto_cond{pool.Create(Variable{}, label_id)}; Statement* const new_goto_cond{pool.Create(Variable{}, label_id, &root_stmt)};
Statement* const new_goto{pool.Create(Goto{}, new_goto_cond, goto_stmt->label, loop->up)}; Statement* const new_goto{pool.Create(Goto{}, new_goto_cond, goto_stmt->label, loop->up)};
Tree& parent_tree{loop->up->children}; Tree& parent_tree{loop->up->children};
return parent_tree.insert(std::next(loop), *new_goto); return parent_tree.insert(std::next(loop), *new_goto);