def METHOD_NAME(self, op: printf.PrintFormatOp, rewriter: PatternRewriter, /):
    format_str = ""
    args: list[SSAValue] = []
    casts: list[Operation] = []
    # make sure all arguments are in the format libc expects them to be
    # e.g. floats must be promoted to double before calling
    for part in _format_string_spec_from_print_op(op):
        if isinstance(part, str):
            format_str += part
        elif isinstance(part.type, builtin.IndexType):
            # index must be cast to fixed bitwidth before printing
            casts.append(new_val := arith.IndexCastOp(part, builtin.i64))
            args.append(new_val.result)
            format_str += "%li"
        elif part.type == builtin.f32:
            # f32 must be promoted to f64 before printing
            casts.append(new_val := arith.ExtFOp(part, builtin.f64))
            args.append(new_val.result)
            format_str += "%f"
        else:
            args.append(part)
            format_str += _format_str_for_type(part.type)
    globl = self._construct_global(format_str + "\n")
    self.collected_global_symbs[globl.sym_name.data] = globl
    rewriter.replace_matched_op(
        casts
        + [
            ptr := llvm.AddressOfOp(globl.sym_name, llvm.LLVMPointerType.opaque()),
            llvm.CallOp("printf", ptr.result, *args),
        ]
    )