|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char sccsid[] = "@(#)p2put.c 5.3 (Berkeley) 6/21/85";
9: #endif not lint
10:
11: /*
12: * functions to help pi put out
13: * polish postfix binary portable c compiler intermediate code
14: * thereby becoming the portable pascal compiler
15: */
16:
17: #include "whoami.h"
18: #ifdef PC
19: #include "0.h"
20: #include "objfmt.h"
21: #include <pcc.h>
22: #include "pc.h"
23: #include "align.h"
24: #include "tmps.h"
25:
26: /*
27: * emits an ftext operator and a string to the pcstream
28: */
29: puttext( string )
30: char *string;
31: {
32: int length = str4len( string );
33:
34: if ( !CGENNING )
35: return;
36: p2word( PCCM_TRIPLE( PCCF_FTEXT , length , 0 ) );
37: # ifdef DEBUG
38: if ( opt( 'k' ) ) {
39: fprintf( stdout , "PCCF_FTEXT | %3d | 0 " , length );
40: }
41: # endif
42: p2string( string );
43: }
44:
45: int
46: str4len( string )
47: char *string;
48: {
49:
50: return ( ( strlen( string ) + 3 ) / 4 );
51: }
52:
53: /*
54: * put formatted text into a buffer for printing to the pcstream.
55: * a call to putpflush actually puts out the text.
56: * none of arg1 .. arg5 need be present.
57: * and you can add more if you need them.
58: */
59: /* VARARGS */
60: putprintf( format , incomplete , arg1 , arg2 , arg3 , arg4 , arg5 )
61: char *format;
62: int incomplete;
63: {
64: static char ppbuffer[ BUFSIZ ];
65: static char *ppbufp = ppbuffer;
66:
67: if ( !CGENNING )
68: return;
69: sprintf( ppbufp , format , arg1 , arg2 , arg3 , arg4 , arg5 );
70: ppbufp = &( ppbuffer[ strlen( ppbuffer ) ] );
71: if ( ppbufp >= &( ppbuffer[ BUFSIZ ] ) )
72: panic( "putprintf" );
73: if ( ! incomplete ) {
74: puttext( ppbuffer );
75: ppbufp = ppbuffer;
76: }
77: }
78:
79: /*
80: * emit a left bracket operator to pcstream
81: * with function number, the maximum temp register, and total local bytes
82: */
83: putlbracket(ftnno, sizesp)
84: int ftnno;
85: struct om *sizesp;
86: {
87: int maxtempreg;
88: int alignedframesize;
89:
90: # ifdef vax
91: maxtempreg = sizesp->curtmps.next_avail[REG_GENERAL];
92: # endif vax
93: # ifdef mc68000
94: /*
95: * this is how /lib/f1 wants it.
96: */
97: maxtempreg = (sizesp->curtmps.next_avail[REG_ADDR] << 4)
98: | (sizesp->curtmps.next_avail[REG_DATA]);
99: # endif mc68000
100: alignedframesize = roundup((int)(BITSPERBYTE * -sizesp->curtmps.om_off),
101: (long)(BITSPERBYTE * A_STACK));
102: p2word( PCCM_TRIPLE( PCCF_FLBRAC , maxtempreg , ftnno ) );
103: p2word(alignedframesize);
104: # ifdef DEBUG
105: if ( opt( 'k' ) ) {
106: fprintf(stdout, "PCCF_FLBRAC | %3d | %d %d\n",
107: maxtempreg, ftnno, alignedframesize);
108: }
109: # endif
110: }
111:
112: /*
113: * emit a right bracket operator
114: * which for the binary interface
115: * forces the stack allocate and register mask
116: */
117: putrbracket( ftnno )
118: int ftnno;
119: {
120:
121: p2word( PCCM_TRIPLE( PCCF_FRBRAC , 0 , ftnno ) );
122: # ifdef DEBUG
123: if ( opt( 'k' ) ) {
124: fprintf( stdout , "PCCF_FRBRAC | 0 | %d\n" , ftnno );
125: }
126: # endif
127: }
128:
129: /*
130: * emit an eof operator
131: */
132: puteof()
133: {
134:
135: p2word( PCCF_FEOF );
136: # ifdef DEBUG
137: if ( opt( 'k' ) ) {
138: fprintf( stdout , "PCCF_FEOF\n" );
139: }
140: # endif
141: }
142:
143: /*
144: * emit a dot operator,
145: * with a source file line number and name
146: * if line is negative, there was an error on that line, but who cares?
147: */
148: putdot( filename , line )
149: char *filename;
150: int line;
151: {
152: int length = str4len( filename );
153:
154: if ( line < 0 ) {
155: line = -line;
156: }
157: p2word( PCCM_TRIPLE( PCCF_FEXPR , length , line ) );
158: # ifdef DEBUG
159: if ( opt( 'k' ) ) {
160: fprintf( stdout , "PCCF_FEXPR | %3d | %d " , length , line );
161: }
162: # endif
163: p2string( filename );
164: }
165:
166: /*
167: * put out a leaf node
168: */
169: putleaf( op , lval , rval , type , name )
170: int op;
171: int lval;
172: int rval;
173: int type;
174: char *name;
175: {
176: if ( !CGENNING )
177: return;
178: switch ( op ) {
179: default:
180: panic( "[putleaf]" );
181: case PCC_ICON:
182: p2word( PCCM_TRIPLE( PCC_ICON , name != NIL , type ) );
183: p2word( lval );
184: # ifdef DEBUG
185: if ( opt( 'k' ) ) {
186: fprintf( stdout , "PCC_ICON | %3d | 0x%x "
187: , name != NIL , type );
188: fprintf( stdout , "%d\n" , lval );
189: }
190: # endif
191: if ( name )
192: p2name( name );
193: break;
194: case PCC_NAME:
195: p2word( PCCM_TRIPLE( PCC_NAME , lval != 0 , type ) );
196: if ( lval )
197: p2word( lval );
198: # ifdef DEBUG
199: if ( opt( 'k' ) ) {
200: fprintf( stdout , "PCC_NAME | %3d | 0x%x "
201: , lval != 0 , type );
202: if ( lval )
203: fprintf( stdout , "%d " , lval );
204: }
205: # endif
206: p2name( name );
207: break;
208: case PCC_REG:
209: p2word( PCCM_TRIPLE( PCC_REG , rval , type ) );
210: # ifdef DEBUG
211: if ( opt( 'k' ) ) {
212: fprintf( stdout , "PCC_REG | %3d | 0x%x\n" ,
213: rval , type );
214: }
215: # endif
216: break;
217: }
218: }
219:
220: /*
221: * rvalues are just lvalues with indirection, except
222: * special cases for registers and for named globals,
223: * whose names are their rvalues.
224: */
225: putRV( name , level , offset , other_flags , type )
226: char *name;
227: int level;
228: int offset;
229: char other_flags;
230: int type;
231: {
232: char extname[ BUFSIZ ];
233: char *printname;
234:
235: if ( !CGENNING )
236: return;
237: if ( other_flags & NREGVAR ) {
238: if ( ( offset < 0 ) || ( offset > P2FP ) ) {
239: panic( "putRV regvar" );
240: }
241: putleaf( PCC_REG , 0 , offset , type , (char *) 0 );
242: return;
243: }
244: if ( whereis( offset , other_flags ) == GLOBALVAR ) {
245: if ( name != 0 ) {
246: if ( name[0] != '_' ) {
247: sprintf( extname , EXTFORMAT , name );
248: printname = extname;
249: } else {
250: printname = name;
251: }
252: putleaf( PCC_NAME , offset , 0 , type , printname );
253: return;
254: } else {
255: panic( "putRV no name" );
256: }
257: }
258: putLV( name , level , offset , other_flags , type );
259: putop( PCCOM_UNARY PCC_MUL , type );
260: }
261:
262: /*
263: * put out an lvalue
264: * given a level and offset
265: * special case for
266: * named globals, whose lvalues are just their names as constants.
267: */
268: putLV( name , level , offset , other_flags , type )
269: char *name;
270: int level;
271: int offset;
272: char other_flags;
273: int type;
274: {
275: char extname[ BUFSIZ ];
276: char *printname;
277:
278: if ( !CGENNING )
279: return;
280: if ( other_flags & NREGVAR ) {
281: panic( "putLV regvar" );
282: }
283: switch ( whereis( offset , other_flags ) ) {
284: case GLOBALVAR:
285: if ( ( name != 0 ) ) {
286: if ( name[0] != '_' ) {
287: sprintf( extname , EXTFORMAT , name );
288: printname = extname;
289: } else {
290: printname = name;
291: }
292: putleaf( PCC_ICON , offset , 0 , PCCM_ADDTYPE( type , PCCTM_PTR )
293: , printname );
294: return;
295: } else {
296: panic( "putLV no name" );
297: }
298: case PARAMVAR:
299: if ( level == cbn ) {
300: putleaf( PCC_REG, 0, P2AP, PCCM_ADDTYPE( type , PCCTM_PTR ), (char *) 0 );
301: } else {
302: putleaf( PCC_NAME , (level * sizeof(struct dispsave)) + AP_OFFSET
303: , 0 , PCCTM_PTR | PCCT_CHAR , DISPLAYNAME );
304: parts[ level ] |= NONLOCALVAR;
305: }
306: putleaf( PCC_ICON , offset , 0 , PCCT_INT , (char *) 0 );
307: putop( PCC_PLUS , PCCTM_PTR | PCCT_CHAR );
308: break;
309: case LOCALVAR:
310: if ( level == cbn ) {
311: putleaf( PCC_REG, 0, P2FP, PCCM_ADDTYPE( type , PCCTM_PTR ), (char *) 0 );
312: } else {
313: putleaf( PCC_NAME , (level * sizeof(struct dispsave)) + FP_OFFSET
314: , 0 , PCCTM_PTR | PCCT_CHAR , DISPLAYNAME );
315: parts[ level ] |= NONLOCALVAR;
316: }
317: putleaf( PCC_ICON , -offset , 0 , PCCT_INT , (char *) 0 );
318: putop( PCC_MINUS , PCCTM_PTR | PCCT_CHAR );
319: break;
320: case NAMEDLOCALVAR:
321: if ( level == cbn ) {
322: putleaf( PCC_REG, 0, P2FP, PCCM_ADDTYPE( type , PCCTM_PTR ), (char *) 0 );
323: } else {
324: putleaf( PCC_NAME , (level * sizeof(struct dispsave)) + FP_OFFSET
325: , 0 , PCCTM_PTR | PCCT_CHAR , DISPLAYNAME );
326: parts[ level ] |= NONLOCALVAR;
327: }
328: putleaf( PCC_ICON , 0 , 0 , PCCT_INT , name );
329: putop( PCC_MINUS , PCCTM_PTR | PCCT_CHAR );
330: break;
331: }
332: return;
333: }
334:
335: /*
336: * put out a floating point constant leaf node
337: * the constant is declared in aligned data space
338: * and a PCC_NAME leaf put out for it
339: */
340: putCON8( val )
341: double val;
342: {
343: char *label;
344: char name[ BUFSIZ ];
345:
346: if ( !CGENNING )
347: return;
348: label = getlab();
349: putprintf( " .data" , 0 );
350: aligndot(A_DOUBLE);
351: (void) putlab( label );
352: # ifdef vax
353: putprintf( " .double 0d%.20e" , 0 , val );
354: # endif vax
355: # ifdef mc68000
356: putprintf( " .long 0x%x,0x%x", 0, val);
357: # endif mc68000
358: putprintf( " .text" , 0 );
359: sprintf( name , PREFIXFORMAT , LABELPREFIX , label );
360: putleaf( PCC_NAME , 0 , 0 , PCCT_DOUBLE , name );
361: }
362:
363: /*
364: * put out either an lvalue or an rvalue for a constant string.
365: * an lvalue (for assignment rhs's) is the name as a constant,
366: * an rvalue (for parameters) is just the name.
367: */
368: putCONG( string , length , required )
369: char *string;
370: int length;
371: int required;
372: {
373: char name[ BUFSIZ ];
374: char *label;
375: char *cp;
376: int pad;
377: int others;
378:
379: if ( !CGENNING )
380: return;
381: putprintf( " .data" , 0 );
382: aligndot(A_STRUCT);
383: label = getlab();
384: (void) putlab( label );
385: cp = string;
386: while ( *cp ) {
387: putprintf( " .byte 0%o" , 1 , *cp ++ );
388: for ( others = 2 ; ( others <= 8 ) && *cp ; others ++ ) {
389: putprintf( ",0%o" , 1 , *cp++ );
390: }
391: putprintf( "" , 0 );
392: }
393: pad = length - strlen( string );
394: while ( pad-- > 0 ) {
395: putprintf( " .byte 0%o" , 1 , ' ' );
396: for ( others = 2 ; ( others <= 8 ) && ( pad-- > 0 ) ; others++ ) {
397: putprintf( ",0%o" , 1 , ' ' );
398: }
399: putprintf( "" , 0 );
400: }
401: putprintf( " .byte 0" , 0 );
402: putprintf( " .text" , 0 );
403: sprintf( name , PREFIXFORMAT , LABELPREFIX , label );
404: if ( required == RREQ ) {
405: putleaf( PCC_NAME , 0 , 0 , PCCTM_ARY | PCCT_CHAR , name );
406: } else {
407: putleaf( PCC_ICON , 0 , 0 , PCCTM_PTR | PCCT_CHAR , name );
408: }
409: }
410:
411: /*
412: * map a pascal type to a c type
413: * this would be tail recursive, but i unfolded it into a for (;;).
414: * this is sort of like isa and lwidth
415: * a note on the types used by the portable c compiler:
416: * they are divided into a basic type (char, short, int, long, etc.)
417: * and qualifications on those basic types (pointer, function, array).
418: * the basic type is kept in the low 4 bits of the type descriptor,
419: * and the qualifications are arranged in two bit chunks, with the
420: * most significant on the right,
421: * and the least significant on the left
422: * e.g. int *foo();
423: * (a function returning a pointer to an integer)
424: * is stored as
425: * <ptr><ftn><int>
426: * so, we build types recursively
427: * also, we know that /lib/f1 can only deal with 6 qualifications
428: * so we stop the recursion there. this stops infinite type recursion
429: * through mutually recursive pointer types.
430: */
431: #define MAXQUALS 6
432: int
433: p2type( np )
434: struct nl *np;
435: {
436:
437: return typerecur( np , 0 );
438: }
439: typerecur( np , quals )
440: struct nl *np;
441: int quals;
442: {
443:
444: if ( np == NIL || quals > MAXQUALS ) {
445: return PCCT_UNDEF;
446: }
447: switch ( np -> class ) {
448: case SCAL :
449: case RANGE :
450: case CRANGE :
451: if ( np -> type == ( nl + TDOUBLE ) ) {
452: return PCCT_DOUBLE;
453: }
454: switch ( bytes( np -> range[0] , np -> range[1] ) ) {
455: case 1:
456: return PCCT_CHAR;
457: case 2:
458: return PCCT_SHORT;
459: case 4:
460: return PCCT_INT;
461: default:
462: panic( "p2type int" );
463: /* NOTREACHED */
464: }
465: case STR :
466: return ( PCCTM_ARY | PCCT_CHAR );
467: case RECORD :
468: case SET :
469: return PCCT_STRTY;
470: case FILET :
471: return ( PCCTM_PTR | PCCT_STRTY );
472: case CONST :
473: case VAR :
474: case FIELD :
475: return p2type( np -> type );
476: case TYPE :
477: switch ( nloff( np ) ) {
478: case TNIL :
479: return ( PCCTM_PTR | PCCT_UNDEF );
480: case TSTR :
481: return ( PCCTM_ARY | PCCT_CHAR );
482: case TSET :
483: return PCCT_STRTY;
484: default :
485: return ( p2type( np -> type ) );
486: }
487: case REF:
488: case WITHPTR:
489: case PTR :
490: return PCCM_ADDTYPE( typerecur( np -> type , quals + 1 ) , PCCTM_PTR );
491: case ARRAY :
492: return PCCM_ADDTYPE( typerecur( np -> type , quals + 1 ) , PCCTM_ARY );
493: case FUNC :
494: /*
495: * functions are really pointers to functions
496: * which return their underlying type.
497: */
498: return PCCM_ADDTYPE( PCCM_ADDTYPE( typerecur( np -> type , quals + 2 ) ,
499: PCCTM_FTN ) , PCCTM_PTR );
500: case PROC :
501: /*
502: * procedures are pointers to functions
503: * which return integers (whether you look at them or not)
504: */
505: return PCCM_ADDTYPE( PCCM_ADDTYPE( PCCT_INT , PCCTM_FTN ) , PCCTM_PTR );
506: case FFUNC :
507: case FPROC :
508: /*
509: * formal procedures and functions are pointers
510: * to structures which describe their environment.
511: */
512: return ( PCCTM_PTR | PCCT_STRTY );
513: default :
514: panic( "p2type" );
515: /* NOTREACHED */
516: }
517: }
518:
519: /*
520: * put a typed operator to the pcstream
521: */
522: putop( op , type )
523: int op;
524: int type;
525: {
526: extern char *p2opname();
527:
528: if ( !CGENNING )
529: return;
530: p2word( PCCM_TRIPLE( op , 0 , type ) );
531: # ifdef DEBUG
532: if ( opt( 'k' ) ) {
533: fprintf( stdout , "%s (%d) | 0 | 0x%x\n"
534: , p2opname( op ) , op , type );
535: }
536: # endif
537: }
538:
539: /*
540: * put out a structure operator (STASG, STARG, STCALL, UNARY STCALL )
541: * which looks just like a regular operator, only the size and
542: * alignment go in the next consecutive words
543: */
544: putstrop( op , type , size , alignment )
545: int op;
546: int type;
547: int size;
548: int alignment;
549: {
550: extern char *p2opname();
551:
552: if ( !CGENNING )
553: return;
554: p2word( PCCM_TRIPLE( op , 0 , type ) );
555: p2word( size );
556: p2word( alignment );
557: # ifdef DEBUG
558: if ( opt( 'k' ) ) {
559: fprintf( stdout , "%s (%d) | 0 | 0x%x %d %d\n"
560: , p2opname( op ) , op , type , size , alignment );
561: }
562: # endif
563: }
564:
565: /*
566: * the string names of p2ops
567: */
568:
569: struct p2op {
570: int op;
571: char *name;
572: };
573:
574: static struct p2op p2opnames[] = {
575: PCC_ERROR, "PCC_ERROR",
576: PCC_NAME, "PCC_NAME",
577: PCC_STRING, "PCC_STRING",
578: PCC_ICON, "PCC_ICON",
579: PCC_FCON, "PCC_FCON",
580: PCC_PLUS, "PCC_PLUS",
581: PCC_MINUS, "PCC_MINUS",
582: PCC_UMINUS, "PCC_UMINUS",
583: PCC_MUL, "PCC_MUL",
584: PCC_DEREF, "PCC_DEREF",
585: PCC_AND, "PCC_AND",
586: PCC_ADDROF, "PCC_ADDROF",
587: PCC_OR, "PCC_OR",
588: PCC_ER, "PCC_ER",
589: PCC_QUEST, "PCC_QUEST",
590: PCC_COLON, "PCC_COLON",
591: PCC_ANDAND, "PCC_ANDAND",
592: PCC_OROR, "PCC_OROR",
593: PCC_CM, "PCC_CM",
594: PCC_ASSIGN, "PCC_ASSIGN",
595: PCC_COMOP, "PCC_COMOP",
596: PCC_DIV, "PCC_DIV",
597: PCC_MOD, "PCC_MOD",
598: PCC_LS, "PCC_LS",
599: PCC_RS, "PCC_RS",
600: PCC_DOT, "PCC_DOT",
601: PCC_STREF, "PCC_STREF",
602: PCC_CALL, "PCC_CALL",
603: PCC_UCALL, "PCC_UCALL",
604: PCC_FORTCALL, "PCC_FORTCALL",
605: PCC_UFORTCALL, "PCC_UFORTCALL",
606: PCC_NOT, "PCC_NOT",
607: PCC_COMPL, "PCC_COMPL",
608: PCC_INCR, "PCC_INCR",
609: PCC_DECR, "PCC_DECR",
610: PCC_EQ, "PCC_EQ",
611: PCC_NE, "PCC_NE",
612: PCC_LE, "PCC_LE",
613: PCC_LT, "PCC_LT",
614: PCC_GE, "PCC_GE",
615: PCC_GT, "PCC_GT",
616: PCC_ULE, "PCC_ULE",
617: PCC_ULT, "PCC_ULT",
618: PCC_UGE, "PCC_UGE",
619: PCC_UGT, "PCC_UGT",
620: PCC_REG, "PCC_REG",
621: PCC_OREG, "PCC_OREG",
622: PCC_CCODES, "PCC_CCODES",
623: PCC_FREE, "PCC_FREE",
624: PCC_STASG, "PCC_STASG",
625: PCC_STARG, "PCC_STARG",
626: PCC_STCALL, "PCC_STCALL",
627: PCC_USTCALL, "PCC_USTCALL",
628: PCC_FLD, "PCC_FLD",
629: PCC_SCONV, "PCC_SCONV",
630: PCC_PCONV, "PCC_PCONV",
631: PCC_PMCONV, "PCC_PMCONV",
632: PCC_PVCONV, "PCC_PVCONV",
633: PCC_FORCE, "PCC_FORCE",
634: PCC_CBRANCH, "PCC_CBRANCH",
635: PCC_INIT, "PCC_INIT",
636: PCC_CAST, "PCC_CAST",
637: -1, ""
638: };
639:
640: char *
641: p2opname( op )
642: register int op;
643: {
644: static char *p2map[PCC_MAXOP+1];
645: static bool mapready = FALSE;
646: register struct p2op *pp;
647:
648: if ( mapready == FALSE ) {
649: for ( pp = p2opnames; pp->op >= 0; pp++ )
650: p2map[ pp->op ] = pp->name;
651: mapready = TRUE;
652: }
653: return ( p2map[ op ] ? p2map[ op ] : "unknown" );
654: }
655:
656: /*
657: * low level routines
658: */
659:
660: /*
661: * puts a long word on the pcstream
662: */
663: p2word( word )
664: int word;
665: {
666:
667: putw( word , pcstream );
668: }
669:
670: /*
671: * put a length 0 mod 4 null padded string onto the pcstream
672: */
673: p2string( string )
674: char *string;
675: {
676: int slen = strlen( string );
677: int wlen = ( slen + 3 ) / 4;
678: int plen = ( wlen * 4 ) - slen;
679: char *cp;
680: int p;
681:
682: for ( cp = string ; *cp ; cp++ )
683: putc( *cp , pcstream );
684: for ( p = 1 ; p <= plen ; p++ )
685: putc( '\0' , pcstream );
686: # ifdef DEBUG
687: if ( opt( 'k' ) ) {
688: fprintf( stdout , "\"%s" , string );
689: for ( p = 1 ; p <= plen ; p++ )
690: fprintf( stdout , "\\0" );
691: fprintf( stdout , "\"\n" );
692: }
693: # endif
694: }
695:
696: /*
697: * puts a name on the pcstream
698: */
699: p2name( name )
700: char *name;
701: {
702: int pad;
703:
704: fprintf( pcstream , NAMEFORMAT , name );
705: pad = strlen( name ) % sizeof (long);
706: for ( ; pad < sizeof (long) ; pad++ ) {
707: putc( '\0' , pcstream );
708: }
709: # ifdef DEBUG
710: if ( opt( 'k' ) ) {
711: fprintf( stdout , NAMEFORMAT , name );
712: pad = strlen( name ) % sizeof (long);
713: for ( ; pad < sizeof (long) ; pad++ ) {
714: fprintf( stdout , "\\0" );
715: }
716: fprintf( stdout , "\n" );
717: }
718: # endif
719: }
720:
721: /*
722: * put out a jump to a label
723: */
724: putjbr( label )
725: long label;
726: {
727:
728: printjbr( LABELPREFIX , label );
729: }
730:
731: /*
732: * put out a jump to any kind of label
733: */
734: printjbr( prefix , label )
735: char *prefix;
736: long label;
737: {
738:
739: # ifdef vax
740: putprintf( " jbr " , 1 );
741: putprintf( PREFIXFORMAT , 0 , prefix , label );
742: # endif vax
743: # ifdef mc68000
744: putprintf( " jra " , 1 );
745: putprintf( PREFIXFORMAT , 0 , prefix , label );
746: # endif mc68000
747: }
748:
749: /*
750: * another version of put to catch calls to put
751: */
752: /* VARARGS */
753: put()
754: {
755:
756: panic("put()");
757: }
758:
759: #endif PC
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.