conflict.c revision 117395
190075Sobrien/* Register conflict graph computation routines. 290075Sobrien Copyright (C) 2000 Free Software Foundation, Inc. 390075Sobrien Contributed by CodeSourcery, LLC 490075Sobrien 590075SobrienThis file is part of GCC. 690075Sobrien 790075SobrienGCC is free software; you can redistribute it and/or modify it under 890075Sobrienthe terms of the GNU General Public License as published by the Free 990075SobrienSoftware Foundation; either version 2, or (at your option) any later 1090075Sobrienversion. 1190075Sobrien 1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1490075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1590075Sobrienfor more details. 1690075Sobrien 1790075SobrienYou should have received a copy of the GNU General Public License 1890075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2090075Sobrien02111-1307, USA. */ 2190075Sobrien 2290075Sobrien/* References: 2390075Sobrien 2490075Sobrien Building an Optimizing Compiler 2590075Sobrien Robert Morgan 2690075Sobrien Butterworth-Heinemann, 1998 */ 2790075Sobrien 2890075Sobrien#include "config.h" 2990075Sobrien#include "system.h" 3090075Sobrien#include "obstack.h" 3190075Sobrien#include "hashtab.h" 3290075Sobrien#include "rtl.h" 3390075Sobrien#include "hard-reg-set.h" 3490075Sobrien#include "basic-block.h" 3590075Sobrien 3690075Sobrien/* A register conflict graph is an undirected graph containing nodes 3790075Sobrien for some or all of the regs used in a function. Arcs represent 3890075Sobrien conflicts, i.e. two nodes are connected by an arc if there is a 3990075Sobrien point in the function at which the regs corresponding to the two 4090075Sobrien nodes are both live. 4190075Sobrien 4290075Sobrien The conflict graph is represented by the data structures described 4390075Sobrien in Morgan section 11.3.1. Nodes are not stored explicitly; only 4490075Sobrien arcs are. An arc stores the numbers of the regs it connects. 4590075Sobrien 4690075Sobrien Arcs can be located by two methods: 4790075Sobrien 4890075Sobrien - The two reg numbers for each arc are hashed into a single 4990075Sobrien value, and the arc is placed in a hash table according to this 5090075Sobrien value. This permits quick determination of whether a specific 5190075Sobrien conflict is present in the graph. 5290075Sobrien 5390075Sobrien - Additionally, the arc data structures are threaded by a set of 5490075Sobrien linked lists by single reg number. Since each arc references 5590075Sobrien two regs, there are two next pointers, one for the 5690075Sobrien smaller-numbered reg and one for the larger-numbered reg. This 5790075Sobrien permits the quick enumeration of conflicts for a single 5890075Sobrien register. 5990075Sobrien 6090075Sobrien Arcs are allocated from an obstack. */ 6190075Sobrien 6290075Sobrien/* An arc in a conflict graph. */ 6390075Sobrien 6490075Sobrienstruct conflict_graph_arc_def 6590075Sobrien{ 6690075Sobrien /* The next element of the list of conflicts involving the 6790075Sobrien smaller-numbered reg, as an index in the table of arcs of this 6890075Sobrien graph. Contains NULL if this is the tail. */ 6990075Sobrien struct conflict_graph_arc_def *smaller_next; 7090075Sobrien 7190075Sobrien /* The next element of the list of conflicts involving the 7290075Sobrien larger-numbered reg, as an index in the table of arcs of this 7390075Sobrien graph. Contains NULL if this is the tail. */ 7490075Sobrien struct conflict_graph_arc_def *larger_next; 7590075Sobrien 7690075Sobrien /* The smaller-numbered reg involved in this conflict. */ 7790075Sobrien int smaller; 7890075Sobrien 7990075Sobrien /* The larger-numbered reg involved in this conflict. */ 8090075Sobrien int larger; 8190075Sobrien}; 8290075Sobrien 8390075Sobrientypedef struct conflict_graph_arc_def *conflict_graph_arc; 8490075Sobrientypedef const struct conflict_graph_arc_def *const_conflict_graph_arc; 8590075Sobrien 8690075Sobrien 8790075Sobrien/* A conflict graph. */ 8890075Sobrien 8990075Sobrienstruct conflict_graph_def 9090075Sobrien{ 9190075Sobrien /* A hash table of arcs. Used to search for a specific conflict. */ 9290075Sobrien htab_t arc_hash_table; 9390075Sobrien 9490075Sobrien /* The number of regs this conflict graph handles. */ 9590075Sobrien int num_regs; 9690075Sobrien 9790075Sobrien /* For each reg, the arc at the head of a list that threads through 9890075Sobrien all the arcs involving that reg. An entry is NULL if no 9990075Sobrien conflicts exist involving that reg. */ 10090075Sobrien conflict_graph_arc *neighbor_heads; 10190075Sobrien 10290075Sobrien /* Arcs are allocated from here. */ 10390075Sobrien struct obstack arc_obstack; 10490075Sobrien}; 10590075Sobrien 10690075Sobrien/* The initial capacity (number of conflict arcs) for newly-created 10790075Sobrien conflict graphs. */ 10890075Sobrien#define INITIAL_ARC_CAPACITY 64 10990075Sobrien 11090075Sobrien 11190075Sobrien/* Computes the hash value of the conflict graph arc connecting regs 11290075Sobrien R1 and R2. R1 is assumed to be smaller or equal to R2. */ 11390075Sobrien#define CONFLICT_HASH_FN(R1, R2) ((R2) * ((R2) - 1) / 2 + (R1)) 11490075Sobrien 115117395Skanstatic hashval_t arc_hash PARAMS ((const void *)); 11690075Sobrienstatic int arc_eq PARAMS ((const void *, const void *)); 11790075Sobrienstatic int print_conflict PARAMS ((int, int, void *)); 11890075Sobrienstatic void mark_reg PARAMS ((rtx, rtx, void *)); 11990075Sobrien 12090075Sobrien/* Callback function to compute the hash value of an arc. Uses 12190075Sobrien current_graph to locate the graph to which the arc belongs. */ 12290075Sobrien 123117395Skanstatic hashval_t 12490075Sobrienarc_hash (arcp) 12590075Sobrien const void *arcp; 12690075Sobrien{ 12790075Sobrien const_conflict_graph_arc arc = (const_conflict_graph_arc) arcp; 12890075Sobrien 12990075Sobrien return CONFLICT_HASH_FN (arc->smaller, arc->larger); 13090075Sobrien} 13190075Sobrien 13290075Sobrien/* Callback function to determine the equality of two arcs in the hash 13390075Sobrien table. */ 13490075Sobrien 13590075Sobrienstatic int 13690075Sobrienarc_eq (arcp1, arcp2) 13790075Sobrien const void *arcp1; 13890075Sobrien const void *arcp2; 13990075Sobrien{ 14090075Sobrien const_conflict_graph_arc arc1 = (const_conflict_graph_arc) arcp1; 14190075Sobrien const_conflict_graph_arc arc2 = (const_conflict_graph_arc) arcp2; 14290075Sobrien 14390075Sobrien return arc1->smaller == arc2->smaller && arc1->larger == arc2->larger; 14490075Sobrien} 14590075Sobrien 14690075Sobrien/* Creates an empty conflict graph to hold conflicts among NUM_REGS 14790075Sobrien registers. */ 14890075Sobrien 14990075Sobrienconflict_graph 15090075Sobrienconflict_graph_new (num_regs) 15190075Sobrien int num_regs; 15290075Sobrien{ 15390075Sobrien conflict_graph graph 15490075Sobrien = (conflict_graph) xmalloc (sizeof (struct conflict_graph_def)); 15590075Sobrien graph->num_regs = num_regs; 15690075Sobrien 15790075Sobrien /* Set up the hash table. No delete action is specified; memory 15890075Sobrien management of arcs is through the obstack. */ 15990075Sobrien graph->arc_hash_table 16090075Sobrien = htab_create (INITIAL_ARC_CAPACITY, &arc_hash, &arc_eq, NULL); 16190075Sobrien 16290075Sobrien /* Create an obstack for allocating arcs. */ 16390075Sobrien obstack_init (&graph->arc_obstack); 16490075Sobrien 16590075Sobrien /* Create and zero the lookup table by register number. */ 16690075Sobrien graph->neighbor_heads 16790075Sobrien = (conflict_graph_arc *) xmalloc (num_regs * sizeof (conflict_graph_arc)); 16890075Sobrien 16990075Sobrien memset (graph->neighbor_heads, 0, num_regs * sizeof (conflict_graph_arc)); 17090075Sobrien return graph; 17190075Sobrien} 17290075Sobrien 17390075Sobrien/* Deletes a conflict graph. */ 17490075Sobrien 17590075Sobrienvoid 17690075Sobrienconflict_graph_delete (graph) 17790075Sobrien conflict_graph graph; 17890075Sobrien{ 17990075Sobrien obstack_free (&graph->arc_obstack, NULL); 18090075Sobrien htab_delete (graph->arc_hash_table); 18190075Sobrien free (graph->neighbor_heads); 18290075Sobrien free (graph); 18390075Sobrien} 18490075Sobrien 18590075Sobrien/* Adds a conflict to GRAPH between regs REG1 and REG2, which must be 186117395Skan distinct. Returns nonzero, unless the conflict is already present 18790075Sobrien in GRAPH, in which case it does nothing and returns zero. */ 18890075Sobrien 18990075Sobrienint 19090075Sobrienconflict_graph_add (graph, reg1, reg2) 19190075Sobrien conflict_graph graph; 19290075Sobrien int reg1; 19390075Sobrien int reg2; 19490075Sobrien{ 19590075Sobrien int smaller = MIN (reg1, reg2); 19690075Sobrien int larger = MAX (reg1, reg2); 19790075Sobrien struct conflict_graph_arc_def dummy; 19890075Sobrien conflict_graph_arc arc; 19990075Sobrien void **slot; 20090075Sobrien 20190075Sobrien /* A reg cannot conflict with itself. */ 20290075Sobrien if (reg1 == reg2) 20390075Sobrien abort (); 20490075Sobrien 20590075Sobrien dummy.smaller = smaller; 20690075Sobrien dummy.larger = larger; 20790075Sobrien slot = htab_find_slot (graph->arc_hash_table, (void *) &dummy, INSERT); 20890075Sobrien 20990075Sobrien /* If the conflict is already there, do nothing. */ 21090075Sobrien if (*slot != NULL) 21190075Sobrien return 0; 21290075Sobrien 21390075Sobrien /* Allocate an arc. */ 21490075Sobrien arc 21590075Sobrien = (conflict_graph_arc) 21690075Sobrien obstack_alloc (&graph->arc_obstack, 21790075Sobrien sizeof (struct conflict_graph_arc_def)); 21890075Sobrien 21990075Sobrien /* Record the reg numbers. */ 22090075Sobrien arc->smaller = smaller; 22190075Sobrien arc->larger = larger; 22290075Sobrien 22390075Sobrien /* Link the conflict into into two lists, one for each reg. */ 22490075Sobrien arc->smaller_next = graph->neighbor_heads[smaller]; 22590075Sobrien graph->neighbor_heads[smaller] = arc; 22690075Sobrien arc->larger_next = graph->neighbor_heads[larger]; 22790075Sobrien graph->neighbor_heads[larger] = arc; 22890075Sobrien 22990075Sobrien /* Put it in the hash table. */ 23090075Sobrien *slot = (void *) arc; 23190075Sobrien 23290075Sobrien return 1; 23390075Sobrien} 23490075Sobrien 235117395Skan/* Returns nonzero if a conflict exists in GRAPH between regs REG1 23690075Sobrien and REG2. */ 23790075Sobrien 23890075Sobrienint 23990075Sobrienconflict_graph_conflict_p (graph, reg1, reg2) 24090075Sobrien conflict_graph graph; 24190075Sobrien int reg1; 24290075Sobrien int reg2; 24390075Sobrien{ 24490075Sobrien /* Build an arc to search for. */ 24590075Sobrien struct conflict_graph_arc_def arc; 24690075Sobrien arc.smaller = MIN (reg1, reg2); 24790075Sobrien arc.larger = MAX (reg1, reg2); 24890075Sobrien 24990075Sobrien return htab_find (graph->arc_hash_table, (void *) &arc) != NULL; 25090075Sobrien} 25190075Sobrien 25290075Sobrien/* Calls ENUM_FN for each conflict in GRAPH involving REG. EXTRA is 25390075Sobrien passed back to ENUM_FN. */ 25490075Sobrien 25590075Sobrienvoid 25690075Sobrienconflict_graph_enum (graph, reg, enum_fn, extra) 25790075Sobrien conflict_graph graph; 25890075Sobrien int reg; 25990075Sobrien conflict_graph_enum_fn enum_fn; 26090075Sobrien void *extra; 26190075Sobrien{ 26290075Sobrien conflict_graph_arc arc = graph->neighbor_heads[reg]; 26390075Sobrien while (arc != NULL) 26490075Sobrien { 26590075Sobrien /* Invoke the callback. */ 26690075Sobrien if ((*enum_fn) (arc->smaller, arc->larger, extra)) 26790075Sobrien /* Stop if requested. */ 26890075Sobrien break; 26990075Sobrien 27090075Sobrien /* Which next pointer to follow depends on whether REG is the 27190075Sobrien smaller or larger reg in this conflict. */ 27290075Sobrien if (reg < arc->larger) 27390075Sobrien arc = arc->smaller_next; 27490075Sobrien else 27590075Sobrien arc = arc->larger_next; 27690075Sobrien } 27790075Sobrien} 27890075Sobrien 27990075Sobrien/* For each conflict between a register x and SRC in GRAPH, adds a 28090075Sobrien conflict to GRAPH between x and TARGET. */ 28190075Sobrien 28290075Sobrienvoid 28390075Sobrienconflict_graph_merge_regs (graph, target, src) 28490075Sobrien conflict_graph graph; 28590075Sobrien int target; 28690075Sobrien int src; 28790075Sobrien{ 28890075Sobrien conflict_graph_arc arc = graph->neighbor_heads[src]; 28990075Sobrien 29090075Sobrien if (target == src) 29190075Sobrien return; 29290075Sobrien 29390075Sobrien while (arc != NULL) 29490075Sobrien { 29590075Sobrien int other = arc->smaller; 29690075Sobrien 29790075Sobrien if (other == src) 29890075Sobrien other = arc->larger; 29990075Sobrien 30090075Sobrien conflict_graph_add (graph, target, other); 30190075Sobrien 30290075Sobrien /* Which next pointer to follow depends on whether REG is the 30390075Sobrien smaller or larger reg in this conflict. */ 30490075Sobrien if (src < arc->larger) 30590075Sobrien arc = arc->smaller_next; 30690075Sobrien else 30790075Sobrien arc = arc->larger_next; 30890075Sobrien } 30990075Sobrien} 31090075Sobrien 31190075Sobrien/* Holds context information while a conflict graph is being traversed 31290075Sobrien for printing. */ 31390075Sobrien 31490075Sobrienstruct print_context 31590075Sobrien{ 31690075Sobrien /* The file pointer to which we're printing. */ 31790075Sobrien FILE *fp; 31890075Sobrien 31990075Sobrien /* The reg whose conflicts we're printing. */ 32090075Sobrien int reg; 32190075Sobrien 32290075Sobrien /* Whether a conflict has already been printed for this reg. */ 32390075Sobrien int started; 32490075Sobrien}; 32590075Sobrien 32690075Sobrien/* Callback function when enumerating conflicts during printing. */ 32790075Sobrien 32890075Sobrienstatic int 32990075Sobrienprint_conflict (reg1, reg2, contextp) 33090075Sobrien int reg1; 33190075Sobrien int reg2; 33290075Sobrien void *contextp; 33390075Sobrien{ 33490075Sobrien struct print_context *context = (struct print_context *) contextp; 33590075Sobrien int reg; 33690075Sobrien 33790075Sobrien /* If this is the first conflict printed for this reg, start a new 33890075Sobrien line. */ 33990075Sobrien if (! context->started) 34090075Sobrien { 34190075Sobrien fprintf (context->fp, " %d:", context->reg); 34290075Sobrien context->started = 1; 34390075Sobrien } 34490075Sobrien 34590075Sobrien /* Figure out the reg whose conflicts we're printing. The other reg 34690075Sobrien is the interesting one. */ 34790075Sobrien if (reg1 == context->reg) 34890075Sobrien reg = reg2; 34990075Sobrien else if (reg2 == context->reg) 35090075Sobrien reg = reg1; 35190075Sobrien else 35290075Sobrien abort (); 35390075Sobrien 35490075Sobrien /* Print the conflict. */ 35590075Sobrien fprintf (context->fp, " %d", reg); 35690075Sobrien 35790075Sobrien /* Continue enumerating. */ 35890075Sobrien return 0; 35990075Sobrien} 36090075Sobrien 36190075Sobrien/* Prints the conflicts in GRAPH to FP. */ 36290075Sobrien 36390075Sobrienvoid 36490075Sobrienconflict_graph_print (graph, fp) 36590075Sobrien conflict_graph graph; 36690075Sobrien FILE *fp; 36790075Sobrien{ 36890075Sobrien int reg; 36990075Sobrien struct print_context context; 37090075Sobrien 37190075Sobrien context.fp = fp; 37290075Sobrien fprintf (fp, "Conflicts:\n"); 37390075Sobrien 37490075Sobrien /* Loop over registers supported in this graph. */ 37590075Sobrien for (reg = 0; reg < graph->num_regs; ++reg) 37690075Sobrien { 37790075Sobrien context.reg = reg; 37890075Sobrien context.started = 0; 37990075Sobrien 38090075Sobrien /* Scan the conflicts for reg, printing as we go. A label for 38190075Sobrien this line will be printed the first time a conflict is 38290075Sobrien printed for the reg; we won't start a new line if this reg 38390075Sobrien has no conflicts. */ 38490075Sobrien conflict_graph_enum (graph, reg, &print_conflict, &context); 38590075Sobrien 38690075Sobrien /* If this reg does have conflicts, end the line. */ 38790075Sobrien if (context.started) 38890075Sobrien fputc ('\n', fp); 38990075Sobrien } 39090075Sobrien} 39190075Sobrien 39290075Sobrien/* Callback function for note_stores. */ 39390075Sobrien 39490075Sobrienstatic void 39590075Sobrienmark_reg (reg, setter, data) 39690075Sobrien rtx reg; 39790075Sobrien rtx setter ATTRIBUTE_UNUSED; 39890075Sobrien void *data; 39990075Sobrien{ 40090075Sobrien regset set = (regset) data; 40190075Sobrien 40290075Sobrien if (GET_CODE (reg) == SUBREG) 40390075Sobrien reg = SUBREG_REG (reg); 40490075Sobrien 40590075Sobrien /* We're only interested in regs. */ 40690075Sobrien if (GET_CODE (reg) != REG) 40790075Sobrien return; 40890075Sobrien 40990075Sobrien SET_REGNO_REG_SET (set, REGNO (reg)); 41090075Sobrien} 41190075Sobrien 41290075Sobrien/* Allocates a conflict graph and computes conflicts over the current 41390075Sobrien function for the registers set in REGS. The caller is responsible 41490075Sobrien for deallocating the return value. 41590075Sobrien 41690075Sobrien Preconditions: the flow graph must be in SSA form, and life 41790075Sobrien analysis (specifically, regs live at exit from each block) must be 41890075Sobrien up-to-date. 41990075Sobrien 42090075Sobrien This algorithm determines conflicts by walking the insns in each 42190075Sobrien block backwards. We maintain the set of live regs at each insn, 42290075Sobrien starting with the regs live on exit from the block. For each insn: 42390075Sobrien 42490075Sobrien 1. If a reg is set in this insns, it must be born here, since 42590075Sobrien we're in SSA. Therefore, it was not live before this insns, 42690075Sobrien so remove it from the set of live regs. 42790075Sobrien 42890075Sobrien 2. For each reg born in this insn, record a conflict between it 42990075Sobrien and every other reg live coming into this insn. For each 43090075Sobrien existing conflict, one of the two regs must be born while the 43190075Sobrien other is alive. See Morgan or elsewhere for a proof of this. 43290075Sobrien 43390075Sobrien 3. Regs clobbered by this insn must have been live coming into 43490075Sobrien it, so record them as such. 43590075Sobrien 43690075Sobrien The resulting conflict graph is not built for regs in REGS 43790075Sobrien themselves; rather, partition P is used to obtain the canonical reg 43890075Sobrien for each of these. The nodes of the conflict graph are these 43990075Sobrien canonical regs instead. */ 44090075Sobrien 44190075Sobrienconflict_graph 44290075Sobrienconflict_graph_compute (regs, p) 44390075Sobrien regset regs; 44490075Sobrien partition p; 44590075Sobrien{ 44690075Sobrien conflict_graph graph = conflict_graph_new (max_reg_num ()); 44790075Sobrien regset_head live_head; 44890075Sobrien regset live = &live_head; 44990075Sobrien regset_head born_head; 45090075Sobrien regset born = &born_head; 451117395Skan basic_block bb; 45290075Sobrien 45390075Sobrien INIT_REG_SET (live); 45490075Sobrien INIT_REG_SET (born); 45590075Sobrien 456117395Skan FOR_EACH_BB_REVERSE (bb) 45790075Sobrien { 45890075Sobrien rtx insn; 45990075Sobrien rtx head; 46090075Sobrien 46190075Sobrien /* Start with the regs that are live on exit, limited to those 46290075Sobrien we're interested in. */ 46390075Sobrien COPY_REG_SET (live, bb->global_live_at_end); 46490075Sobrien AND_REG_SET (live, regs); 46590075Sobrien 46690075Sobrien /* Walk the instruction stream backwards. */ 46790075Sobrien head = bb->head; 46890075Sobrien insn = bb->end; 46990075Sobrien for (insn = bb->end; insn != head; insn = PREV_INSN (insn)) 47090075Sobrien { 47190075Sobrien int born_reg; 47290075Sobrien int live_reg; 47390075Sobrien rtx link; 47490075Sobrien 47590075Sobrien /* Are we interested in this insn? */ 47690075Sobrien if (INSN_P (insn)) 47790075Sobrien { 47890075Sobrien /* Determine which regs are set in this insn. Since 47990075Sobrien we're in SSA form, if a reg is set here it isn't set 48090075Sobrien anywhere else, so this insn is where the reg is born. */ 48190075Sobrien CLEAR_REG_SET (born); 48290075Sobrien note_stores (PATTERN (insn), mark_reg, born); 48390075Sobrien AND_REG_SET (born, regs); 48490075Sobrien 48590075Sobrien /* Regs born here were not live before this insn. */ 48690075Sobrien AND_COMPL_REG_SET (live, born); 48790075Sobrien 48890075Sobrien /* For every reg born here, add a conflict with every other 48990075Sobrien reg live coming into this insn. */ 49090075Sobrien EXECUTE_IF_SET_IN_REG_SET 49190075Sobrien (born, FIRST_PSEUDO_REGISTER, born_reg, 49290075Sobrien { 49390075Sobrien EXECUTE_IF_SET_IN_REG_SET 49490075Sobrien (live, FIRST_PSEUDO_REGISTER, live_reg, 49590075Sobrien { 49690075Sobrien /* Build the conflict graph in terms of canonical 49790075Sobrien regnos. */ 49890075Sobrien int b = partition_find (p, born_reg); 49990075Sobrien int l = partition_find (p, live_reg); 50090075Sobrien 50190075Sobrien if (b != l) 50290075Sobrien conflict_graph_add (graph, b, l); 50390075Sobrien }); 50490075Sobrien }); 50590075Sobrien 50690075Sobrien /* Morgan's algorithm checks the operands of the insn 50790075Sobrien and adds them to the set of live regs. Instead, we 50890075Sobrien use death information added by life analysis. Regs 50990075Sobrien dead after this instruction were live before it. */ 51090075Sobrien for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) 51190075Sobrien if (REG_NOTE_KIND (link) == REG_DEAD) 51290075Sobrien { 51390075Sobrien unsigned int regno = REGNO (XEXP (link, 0)); 51490075Sobrien 51590075Sobrien if (REGNO_REG_SET_P (regs, regno)) 51690075Sobrien SET_REGNO_REG_SET (live, regno); 51790075Sobrien } 51890075Sobrien } 51990075Sobrien } 52090075Sobrien } 52190075Sobrien 52290075Sobrien FREE_REG_SET (live); 52390075Sobrien FREE_REG_SET (born); 52490075Sobrien 52590075Sobrien return graph; 52690075Sobrien} 527