@@ -52,18 +52,6 @@ public PackedStructureMember (StructureMemberInfo<T> memberInfo, object? value,
5252 }
5353 }
5454
55- public sealed class StringSymbolInfo
56- {
57- public readonly string SymbolName ;
58- public readonly ulong Size ;
59-
60- public StringSymbolInfo ( string symbolName , ulong size )
61- {
62- SymbolName = symbolName ;
63- Size = size ;
64- }
65- }
66-
6755 static readonly Dictionary < Type , string > typeMap = new Dictionary < Type , string > {
6856 { typeof ( bool ) , "i8" } ,
6957 { typeof ( byte ) , "i8" } ,
@@ -165,11 +153,13 @@ public StringSymbolInfo (string symbolName, ulong size)
165153 public AndroidTargetArch TargetArch { get ; }
166154
167155 protected LlvmIrMetadataManager MetadataManager { get ; }
156+ protected LlvmIrStringManager StringManager { get ; }
168157
169158 protected LlvmIrGenerator ( AndroidTargetArch arch , TextWriter output , string fileName )
170159 {
171160 Output = output ;
172161 MetadataManager = new LlvmIrMetadataManager ( ) ;
162+ StringManager = new LlvmIrStringManager ( ) ;
173163 TargetArch = arch ;
174164 Is64Bit = arch == AndroidTargetArch . X86_64 || arch == AndroidTargetArch . Arm64 ;
175165 this . fileName = fileName ;
@@ -455,7 +445,7 @@ bool MaybeWriteStructureString<T> (StructureInfo<T> info, StructureMemberInfo<T>
455445 return false ;
456446 }
457447
458- StringSymbolInfo stringSymbol = WriteUniqueString ( $ "__{ info . Name } _{ smi . Info . Name } ", str , ref structStringCounter ) ;
448+ StringSymbolInfo stringSymbol = StringManager . Add ( str , groupName : info . Name , symbolSuffix : smi . Info . Name ) ; // WriteUniqueString ($"__{info.Name}_{smi.Info.Name}", str, ref structStringCounter);
459449 instance . AddPointerData ( smi , stringSymbol . SymbolName , stringSymbol . Size ) ;
460450
461451 return true ;
@@ -622,12 +612,11 @@ public void WriteArray (IList<string> values, string symbolName, string? initial
622612 WriteEOL ( ) ;
623613 WriteEOL ( initialComment ?? symbolName ) ;
624614
625- ulong arrayStringCounter = 0 ;
626- var strings = new List < StringSymbolInfo > ( ) ;
615+ var strings = new List < StringSymbolInfo > ( ) ;
627616
628617 foreach ( string s in values ) {
629- StringSymbolInfo symbol = WriteUniqueString ( $ "__ { symbolName } " , s , ref arrayStringCounter , LlvmIrVariableOptions . LocalConstexprString ) ;
630- strings . Add ( new StringSymbolInfo ( symbol . SymbolName , symbol . Size ) ) ;
618+ StringSymbolInfo symbol = StringManager . Add ( s , groupName : symbolName ) ;
619+ strings . Add ( symbol ) ;
631620 }
632621
633622 if ( strings . Count > 0 ) {
@@ -1137,12 +1126,12 @@ void WriteBufferToOutput (TextWriter? writer)
11371126 }
11381127 }
11391128
1140- void WriteGetStringPointer ( string ? variableName , ulong size , bool indent = true , TextWriter ? output = null )
1129+ void WriteGetStringPointer ( string ? variableName , ulong size , bool indent = true , TextWriter ? output = null , bool detectBitness = false , bool skipPointerType = false )
11411130 {
1142- WriteGetBufferPointer ( variableName , "i8*" , size , indent , output ) ;
1131+ WriteGetBufferPointer ( variableName , "i8*" , size , indent , output , detectBitness , skipPointerType ) ;
11431132 }
11441133
1145- void WriteGetBufferPointer ( string ? variableName , string irType , ulong size , bool indent = true , TextWriter ? output = null )
1134+ void WriteGetBufferPointer ( string ? variableName , string irType , ulong size , bool indent = true , TextWriter ? output = null , bool detectBitness = false , bool skipPointerType = false )
11461135 {
11471136 output = EnsureOutput ( output ) ;
11481137 if ( indent ) {
@@ -1160,8 +1149,12 @@ void WriteGetBufferPointer (string? variableName, string irType, ulong size, boo
11601149 irBaseType = irType ;
11611150 }
11621151
1152+ string indexType = detectBitness && Is64Bit ? "i64" : "i32" ;
11631153 // $"{irType} getelementptr inbounds ([{size} x {irBaseType}], [{size} x {irBaseType}]* @{variableName}, i32 0, i32 0)"
1164- output . Write ( irType ) ;
1154+ if ( ! skipPointerType ) {
1155+ output . Write ( irType ) ;
1156+ }
1157+
11651158 output . Write ( " getelementptr inbounds ([" ) ;
11661159 output . Write ( size ) ;
11671160 output . Write ( " x " ) ;
@@ -1172,7 +1165,11 @@ void WriteGetBufferPointer (string? variableName, string irType, ulong size, boo
11721165 output . Write ( irBaseType ) ;
11731166 output . Write ( "]* @" ) ;
11741167 output . Write ( variableName ) ;
1175- output . Write ( ", i32 0, i32 0)" ) ;
1168+ output . Write ( ", " ) ;
1169+ output . Write ( indexType ) ;
1170+ output . Write ( " 0, " ) ;
1171+ output . Write ( indexType ) ;
1172+ output . Write ( " 0)" ) ;
11761173 }
11771174 }
11781175
@@ -1186,7 +1183,6 @@ public void WriteNameValueArray (string symbolName, IDictionary<string, string>
11861183
11871184 var strings = new List < StringSymbolInfo > ( ) ;
11881185 long i = 0 ;
1189- ulong arrayStringCounter = 0 ;
11901186
11911187 foreach ( var kvp in arrayContents ) {
11921188 string name = kvp . Key ;
@@ -1205,8 +1201,8 @@ public void WriteNameValueArray (string symbolName, IDictionary<string, string>
12051201
12061202 void WriteArrayString ( string str , string symbolSuffix )
12071203 {
1208- StringSymbolInfo symbol = WriteUniqueString ( $ "__ { symbolName } _ { symbolSuffix } " , str , ref arrayStringCounter , LlvmIrVariableOptions . LocalConstexprString ) ;
1209- strings . Add ( new StringSymbolInfo ( symbol . SymbolName , symbol . Size ) ) ;
1204+ StringSymbolInfo symbol = StringManager . Add ( str , groupName : symbolName , symbolSuffix : symbolSuffix ) ;
1205+ strings . Add ( symbol ) ;
12101206 }
12111207 }
12121208
@@ -1279,28 +1275,6 @@ public void WriteVariable<T> (string symbolName, T value, LlvmIrVariableOptions
12791275 Output . WriteLine ( size ) ;
12801276 }
12811277
1282- /// <summary>
1283- /// Writes a private string. Strings without symbol names aren't exported, but they may be referenced by other
1284- /// symbols
1285- /// </summary>
1286- public string WriteString ( string value )
1287- {
1288- return WriteString ( value , LlvmIrVariableOptions . LocalString ) ;
1289- }
1290-
1291- /// <summary>
1292- /// Writes a string with automatically generated symbol name and symbol options (writeability, visibility etc) specified in the <paramref name="options"/> parameter.
1293- /// </summary>
1294- public string WriteString ( string value , LlvmIrVariableOptions options )
1295- {
1296- string name = $ "@.str";
1297- if ( stringCounter > 0 ) {
1298- name += $ ".{ stringCounter } ";
1299- }
1300- stringCounter ++ ;
1301- return WriteString ( name , value , options ) ;
1302- }
1303-
13041278 /// <summary>
13051279 /// Writes a global, C++ constexpr style string
13061280 /// </summary>
@@ -1317,101 +1291,27 @@ public string WriteString (string symbolName, string value, LlvmIrVariableOption
13171291 return WriteString ( symbolName , value , options , out _ ) ;
13181292 }
13191293
1320- /// <summary>
1321- /// Writes a local, constexpr style string and returns its size in <paramref name="stringSize"/>
1322- /// </summary>
1323- public string WriteString ( string symbolName , string value , out ulong stringSize )
1324- {
1325- return WriteString ( symbolName , value , LlvmIrVariableOptions . LocalConstexprString , out stringSize ) ;
1326- }
1327-
13281294 /// <summary>
13291295 /// Writes a string with specified <paramref name="symbolName"/>, and symbol options (writeability, visibility etc) specified in the <paramref name="options"/>
13301296 /// parameter. Returns string size (in bytes) in <paramref name="stringSize"/>
13311297 /// </summary>
13321298 public string WriteString ( string symbolName , string value , LlvmIrVariableOptions options , out ulong stringSize )
13331299 {
1334- string strSymbolName ;
1335- bool global = options . IsGlobal ;
1336- if ( global ) {
1337- strSymbolName = $ "__{ symbolName } ";
1338- } else {
1339- strSymbolName = symbolName ;
1340- }
1341-
1342- string quotedString = QuoteString ( value , out stringSize ) ;
1343-
1344- // It might seem counter-intuitive that when we're requested to write a global string, here we generate a **local** one,
1345- // but global strings are actually pointers to local storage.
1346- WriteGlobalSymbolStart ( strSymbolName , global ? LlvmIrVariableOptions . LocalConstexprString : options ) ;
1347-
1348- // WriteLine $"[{stringSize} x i8] c{quotedString}, align {GetAggregateAlignment (1, stringSize)}"
1349- Output . Write ( '[' ) ;
1350- Output . Write ( stringSize ) ;
1351- Output . Write ( " x i8] c" ) ;
1352- Output . Write ( quotedString ) ;
1353- Output . Write ( ", align " ) ;
1354- Output . WriteLine ( GetAggregateAlignment ( 1 , stringSize ) ) ;
1355-
1356- if ( ! global ) {
1300+ StringSymbolInfo info = StringManager . Add ( value , groupName : symbolName ) ;
1301+ stringSize = info . Size ;
1302+ if ( ! options . IsGlobal ) {
13571303 return symbolName ;
13581304 }
13591305
13601306 string indexType = Is64Bit ? "i64" : "i32" ;
13611307 WriteGlobalSymbolStart ( symbolName , LlvmIrVariableOptions . GlobalConstantStringPointer ) ;
1362-
1363- // WriteLine $"i8* getelementptr inbounds ([{stringSize} x i8], [{stringSize} x i8]* @{strSymbolName}, {indexType} 0, {indexType} 0), align {GetAggregateAlignment (PointerSize, stringSize)}"
1364- Output . Write ( "i8* getelementptr inbounds ([" ) ;
1365- Output . Write ( stringSize ) ;
1366- Output . Write ( " x i8], [" ) ;
1367- Output . Write ( stringSize ) ;
1368- Output . Write ( " x i8]* @" ) ;
1369- Output . Write ( strSymbolName ) ;
1370- Output . Write ( ", " ) ;
1371- Output . Write ( indexType ) ;
1372- Output . Write ( " 0, " ) ;
1373- Output . Write ( indexType ) ;
1374- Output . Write ( " 0), align " ) ;
1308+ WriteGetStringPointer ( info . SymbolName , info . Size , indent : false , detectBitness : true ) ;
1309+ Output . Write ( ", align " ) ;
13751310 Output . WriteLine ( GetAggregateAlignment ( PointerSize , stringSize ) ) ;
13761311
13771312 return symbolName ;
13781313 }
13791314
1380- /// <summary>
1381- /// Writes a string, creating a new symbol if the <paramref name="value"/> is unique or returns name of a previously created symbol with the same
1382- /// string value. If a new symbol is written, its name is constructed by combining prefix (<paramref name="potentialSymbolNamePrefix"/>) with value
1383- /// of a string counter referenced by the <paramref name="counter"/> parameter. Symbol is created as a local, C++ constexpr style string.
1384- /// </summary>
1385- public StringSymbolInfo WriteUniqueString ( string potentialSymbolName , string value , ref ulong counter )
1386- {
1387- return WriteUniqueString ( potentialSymbolName , value , ref counter , LlvmIrVariableOptions . LocalConstexprString ) ;
1388- }
1389-
1390- /// <summary>
1391- /// Writes a string, creating a new symbol if the <paramref name="value"/> is unique or returns name of a previously created symbol with the same
1392- /// string value. If a new symbol is written, its name is constructed by combining prefix (<paramref name="potentialSymbolNamePrefix"/>) with value
1393- /// of a string counter referenced by the <paramref name="counter"/> parameter. Symbol options (writeability, visibility etc) are specified in the <paramref
1394- /// name="options"/> parameter. String size (in bytes) is returned in <paramref name="stringSize"/>.
1395- /// </summary>
1396- public StringSymbolInfo WriteUniqueString ( string potentialSymbolNamePrefix , string value , ref ulong counter , LlvmIrVariableOptions options )
1397- {
1398- if ( value == null ) {
1399- return null ;
1400- }
1401-
1402- StringSymbolInfo info ;
1403- if ( stringSymbolCache . TryGetValue ( value , out info ) ) {
1404- return info ;
1405- }
1406-
1407- string newSymbolName = $ "{ potentialSymbolNamePrefix } .{ counter ++ } ";
1408- WriteString ( newSymbolName , value , options , out ulong stringSize ) ;
1409- info = new StringSymbolInfo ( newSymbolName , stringSize ) ;
1410- stringSymbolCache . Add ( value , info ) ;
1411-
1412- return info ;
1413- }
1414-
14151315 public virtual void WriteFileTop ( )
14161316 {
14171317 WriteCommentLine ( $ "ModuleID = '{ fileName } '") ;
@@ -1423,7 +1323,9 @@ public virtual void WriteFileTop ()
14231323 public virtual void WriteFileEnd ( )
14241324 {
14251325 Output . WriteLine ( ) ;
1326+ StringManager . Flush ( this ) ;
14261327
1328+ Output . WriteLine ( ) ;
14271329 WriteAttributeSets ( ) ;
14281330
14291331 foreach ( LlvmIrMetadataItem metadata in MetadataManager . Items ) {
0 commit comments