primIfElse merges the basic blocks of the given if_else-primitive into a corresponding conceputal basic block for the primitive.
(condBlock, bodyTrueBlock, bodyFalseBlock, exitBlock *basicBlock)
| 186 | // primIfElse merges the basic blocks of the given if_else-primitive into a |
| 187 | // corresponding conceputal basic block for the primitive. |
| 188 | func (d *decompiler) primIfElse(condBlock, bodyTrueBlock, bodyFalseBlock, exitBlock *basicBlock) (*basicBlock, error) { |
| 189 | // Handle terminators. |
| 190 | var cond ast.Expr |
| 191 | switch condTerm := condBlock.Term.(type) { |
| 192 | case *ir.TermCondBr: |
| 193 | cond = d.value(condTerm.Cond) |
| 194 | case *ir.TermSwitch: |
| 195 | cases := condTerm.Cases |
| 196 | if len(cases) != 1 { |
| 197 | return nil, errors.Errorf("invalid number of switch cases in if_else primitive; expected 1, got %d", len(cases)) |
| 198 | } |
| 199 | cond = &ast.BinaryExpr{ |
| 200 | X: d.value(condTerm.X), |
| 201 | Op: token.EQL, |
| 202 | Y: d.constant(cases[0].X), |
| 203 | } |
| 204 | default: |
| 205 | return nil, errors.Errorf("invalid cond terminator type; expected *ir.TermCondBr, got %T", condBlock.Term) |
| 206 | } |
| 207 | // TODO: Figure out a clean way to check if the body_true basic block is the |
| 208 | // true branch or the false branch. If body_true is the false branch, use |
| 209 | // body_true for the else body of the if-statement. |
| 210 | if _, ok := bodyTrueBlock.Term.(*ir.TermBr); !ok { |
| 211 | return nil, errors.Errorf("invalid body_true terminator type; expected *ir.TermBr, got %T", bodyTrueBlock.Term) |
| 212 | } |
| 213 | if _, ok := bodyFalseBlock.Term.(*ir.TermBr); !ok { |
| 214 | return nil, errors.Errorf("invalid body_false terminator type; expected *ir.TermBr, got %T", bodyFalseBlock.Term) |
| 215 | } |
| 216 | block := &basicBlock{BasicBlock: &ir.BasicBlock{}} |
| 217 | block.Term = exitBlock.Term |
| 218 | // Handle instructions. |
| 219 | block.stmts = append(block.stmts, d.stmts(condBlock)...) |
| 220 | bodyTrue := &ast.BlockStmt{ |
| 221 | List: d.stmts(bodyTrueBlock), |
| 222 | } |
| 223 | bodyFalse := &ast.BlockStmt{ |
| 224 | List: d.stmts(bodyFalseBlock), |
| 225 | } |
| 226 | ifElseStmt := &ast.IfStmt{ |
| 227 | Cond: cond, |
| 228 | Body: bodyTrue, |
| 229 | Else: bodyFalse, |
| 230 | } |
| 231 | block.stmts = append(block.stmts, ifElseStmt) |
| 232 | block.stmts = append(block.stmts, d.stmts(exitBlock)...) |
| 233 | return block, nil |
| 234 | } |
| 235 | |
| 236 | // primIfReturn merges the basic blocks of the given if_return-primitive into a |
| 237 | // corresponding conceputal basic block for the primitive. |