|
52 | 52 | interface |
53 | 53 |
|
54 | 54 | uses |
| 55 | + WinApi.Windows, |
55 | 56 | System.Types, |
56 | 57 | System.SysUtils, |
57 | 58 | System.AnsiStrings, |
58 | 59 | System.TypInfo, |
59 | 60 | System.Classes, |
60 | 61 | System.Rtti, |
61 | 62 | System.Math, |
| 63 | + System.IOUtils, |
62 | 64 | System.Generics.Collections, |
63 | 65 | libLLVM.API, |
64 | 66 | libLLVM.Utils; |
@@ -112,6 +114,14 @@ interface |
112 | 114 | ccFastCall // LLVMX86FastcallCallConv |
113 | 115 | ); |
114 | 116 |
|
| 117 | + { TLLOptimization } |
| 118 | + TLLOptimization = ( |
| 119 | + olDebug, // No optimization - best for debugging |
| 120 | + olSize, // Optimize for size/compile speed |
| 121 | + olSpeed, // Balanced speed optimization (default) |
| 122 | + olMaximum // Maximum optimization |
| 123 | + ); |
| 124 | + |
115 | 125 | { TLLParam } |
116 | 126 | TLLParam = record |
117 | 127 | ParamName: string; |
@@ -164,6 +174,7 @@ TLLVM = class |
164 | 174 | function GetBasicType(const ABasicType: TLLDataType; const AContext: LLVMContextRef): LLVMTypeRef; |
165 | 175 | function GetLLVMCallingConv(const ACallingConv: TLLCallingConv): LLVMCallConv; |
166 | 176 | function GetLLVMLinkage(const AVisibility: TLLVisibility): LLVMLinkage; |
| 177 | + function GetLLVMOptLevel(const AOptLevel: TLLOptimization): LLVMCodeGenOptLevel; |
167 | 178 | {$HINTS OFF} |
168 | 179 | function LLVMTypeToBasicType(ALLVMType: LLVMTypeRef): TLLDataType; |
169 | 180 | {$HINTS ON} |
@@ -203,6 +214,13 @@ TLLVM = class |
203 | 214 | function ValidateModule(const AModuleId: string): Boolean; |
204 | 215 | function GetRequiredLibraries(const AModuleId: string): TArray<string>; |
205 | 216 |
|
| 217 | + // Object file compilation |
| 218 | + class function GetObjectFileExtension(): string; static; |
| 219 | + function CompileModuleToObject(const AModuleId: string; const AOutputPath: string = ''; |
| 220 | + const AOptLevel: TLLOptimization = olSpeed): string; |
| 221 | + function CompileAllModulesToObjects(const AOutputDirectory: string; |
| 222 | + const AOptLevel: TLLOptimization = olSpeed): TArray<string>; |
| 223 | + |
206 | 224 | // Function declaration |
207 | 225 | function BeginFunction(const AModuleId: string; const AFunctionName: string; const AReturnType: TLLDataType; |
208 | 226 | const AParams: array of TLLParam; const AVisibility: TLLVisibility = vPublic; |
@@ -488,6 +506,19 @@ class function TLLVM.GetLLVMVersionStr(): string; |
488 | 506 | Result := Format('%d.%d.%d', [LMajor, LMinor, LPatch]); |
489 | 507 | end; |
490 | 508 |
|
| 509 | +class function TLLVM.GetObjectFileExtension(): string; |
| 510 | +begin |
| 511 | + {$IFDEF MSWINDOWS} |
| 512 | + Result := '.obj'; |
| 513 | + {$ELSE} |
| 514 | + {$IFDEF DARWIN} |
| 515 | + Result := '.o'; |
| 516 | + {$ELSE} |
| 517 | + Result := '.o'; // Linux and other Unix-like systems |
| 518 | + {$ENDIF} |
| 519 | + {$ENDIF} |
| 520 | +end; |
| 521 | + |
491 | 522 | function TLLVM.SetTargetPlatform(const ATriple: string; const ADataLayout: string): TLLVM; |
492 | 523 | begin |
493 | 524 | FTargetTriple := ATriple; |
@@ -563,6 +594,18 @@ function TLLVM.GetLLVMLinkage(const AVisibility: TLLVisibility): LLVMLinkage; |
563 | 594 | end; |
564 | 595 | end; |
565 | 596 |
|
| 597 | +function TLLVM.GetLLVMOptLevel(const AOptLevel: TLLOptimization): LLVMCodeGenOptLevel; |
| 598 | +begin |
| 599 | + case AOptLevel of |
| 600 | + olDebug: Result := LLVMCodeGenLevelNone; |
| 601 | + olSize: Result := LLVMCodeGenLevelLess; |
| 602 | + olSpeed: Result := LLVMCodeGenLevelDefault; |
| 603 | + olMaximum: Result := LLVMCodeGenLevelAggressive; |
| 604 | + else |
| 605 | + Result := LLVMCodeGenLevelDefault; |
| 606 | + end; |
| 607 | +end; |
| 608 | + |
566 | 609 | function TLLVM.LLVMTypeToBasicType(ALLVMType: LLVMTypeRef): TLLDataType; |
567 | 610 | var |
568 | 611 | LKind: LLVMTypeKind; |
@@ -839,6 +882,101 @@ function TLLVM.GetRequiredLibraries(const AModuleId: string): TArray<string>; |
839 | 882 | SetLength(Result, 0); |
840 | 883 | end; |
841 | 884 |
|
| 885 | +function TLLVM.CompileModuleToObject(const AModuleId: string; const AOutputPath: string; |
| 886 | + const AOptLevel: TLLOptimization): string; |
| 887 | +var |
| 888 | + LModuleState: TLLModuleState; |
| 889 | + LTargetMachine: LLVMTargetMachineRef; |
| 890 | + LTarget: LLVMTargetRef; |
| 891 | + LTriple: PAnsiChar; |
| 892 | + LCPU: PAnsiChar; |
| 893 | + LFeatures: PAnsiChar; |
| 894 | + LError: PAnsiChar; |
| 895 | + LOutputDir: string; |
| 896 | + LFileName: string; |
| 897 | + LFullPath: string; |
| 898 | +begin |
| 899 | + LModuleState := GetModuleState(AModuleId); |
| 900 | + |
| 901 | + // Always auto-generate filename from module ID |
| 902 | + LFileName := TPath.ChangeExtension(AModuleId, GetObjectFileExtension()); |
| 903 | + |
| 904 | + // Handle directory - default to current if empty |
| 905 | + if AOutputPath = '' then |
| 906 | + LOutputDir := TDirectory.GetCurrentDirectory() |
| 907 | + else |
| 908 | + LOutputDir := AOutputPath; |
| 909 | + |
| 910 | + // Ensure directory exists |
| 911 | + if not TDirectory.Exists(LOutputDir) then |
| 912 | + TDirectory.CreateDirectory(LOutputDir); |
| 913 | + |
| 914 | + // Combine directory + filename using TPath |
| 915 | + LFullPath := TPath.Combine(LOutputDir, LFileName); |
| 916 | + |
| 917 | + // Get target information |
| 918 | + LTriple := LLVMGetDefaultTargetTriple(); |
| 919 | + LCPU := LLVMGetHostCPUName(); |
| 920 | + LFeatures := LLVMGetHostCPUFeatures(); |
| 921 | + |
| 922 | + try |
| 923 | + // Find target for triple |
| 924 | + if LLVMGetTargetFromTriple(LTriple, @LTarget, @LError) <> 0 then |
| 925 | + begin |
| 926 | + LLVMDisposeMessage(LError); |
| 927 | + raise Exception.CreateFmt('Failed to get target for triple %s', [string(UTF8String(LTriple))]); |
| 928 | + end; |
| 929 | + |
| 930 | + // Create target machine |
| 931 | + LTargetMachine := LLVMCreateTargetMachine(LTarget, LTriple, LCPU, LFeatures, |
| 932 | + GetLLVMOptLevel(AOptLevel), LLVMRelocDefault, LLVMCodeModelDefault); |
| 933 | + if LTargetMachine = nil then |
| 934 | + raise Exception.Create('Failed to create target machine'); |
| 935 | + |
| 936 | + try |
| 937 | + // Emit to object file |
| 938 | + if LLVMTargetMachineEmitToFile(LTargetMachine, LModuleState.Module, |
| 939 | + PAnsiChar(AnsiString(LFullPath)), LLVMObjectFile, @LError) <> 0 then |
| 940 | + begin |
| 941 | + LLVMDisposeMessage(LError); |
| 942 | + raise Exception.CreateFmt('Failed to emit object file: %s', [LFullPath]); |
| 943 | + end; |
| 944 | + |
| 945 | + Result := LFullPath; |
| 946 | + finally |
| 947 | + LLVMDisposeTargetMachine(LTargetMachine); |
| 948 | + end; |
| 949 | + finally |
| 950 | + LLVMDisposeMessage(LTriple); |
| 951 | + LLVMDisposeMessage(LCPU); |
| 952 | + LLVMDisposeMessage(LFeatures); |
| 953 | + end; |
| 954 | +end; |
| 955 | + |
| 956 | +function TLLVM.CompileAllModulesToObjects(const AOutputDirectory: string; |
| 957 | + const AOptLevel: TLLOptimization): TArray<string>; |
| 958 | +var |
| 959 | + LModulePair: TPair<string, TLLModuleState>; |
| 960 | + LResults: TList<string>; |
| 961 | +begin |
| 962 | + LResults := TList<string>.Create(); |
| 963 | + try |
| 964 | + // Ensure output directory exists |
| 965 | + if not TDirectory.Exists(AOutputDirectory) then |
| 966 | + TDirectory.CreateDirectory(AOutputDirectory); |
| 967 | + |
| 968 | + // Compile each module |
| 969 | + for LModulePair in FModules do |
| 970 | + begin |
| 971 | + LResults.Add(CompileModuleToObject(LModulePair.Key, AOutputDirectory, AOptLevel)); |
| 972 | + end; |
| 973 | + |
| 974 | + Result := LResults.ToArray(); |
| 975 | + finally |
| 976 | + LResults.Free(); |
| 977 | + end; |
| 978 | +end; |
| 979 | + |
842 | 980 | // Function declaration |
843 | 981 | function TLLVM.BeginFunction(const AModuleId: string; const AFunctionName: string; const AReturnType: TLLDataType; |
844 | 982 | const AParams: array of TLLParam; const AVisibility: TLLVisibility; const ACallingConv: TLLCallingConv; |
|
0 commit comments