Skip to content

Commit 681d8d4

Browse files
committed
Repo Update
- Add TLLVM.CompileModuleToObject() method for single module compilation - Add TLLVM.CompileAllModulesToObjects() method for batch compilation - Add TLLVM.GetObjectFileExtension() class method for platform-specific extensions - Add libLLVM.Test.ObjectCompilation unit with comprehensive test coverage - Add TestSingleModuleCompilation() test method - Add TestBatchModuleCompilation() test method - Add TestOptimizationLevels() test method - Add TestFileExtensions() test method - Add TestOutputDirectories() test method - Add TestErrorConditions() test method - Add TestFileVerification() test method - Modernize all file operations to use TFile/TDirectory/TPath APIs - Implement consistent ModuleId + extension filename strategy - Add automatic directory creation for output paths
1 parent a22c301 commit 681d8d4

File tree

6 files changed

+894
-3
lines changed

6 files changed

+894
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,4 @@ changes.diff
9090
zip_latest_commit.cmd
9191
!/bin/libs/*
9292
checkpoint.zip
93+
bin/output

examples/testbed/Testbed.dpr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ uses
3939
libLLVM.Test.Values in '..\..\src\tests\libLLVM.Test.Values.pas',
4040
libLLVM.Test.Variable in '..\..\src\tests\libLLVM.Test.Variable.pas',
4141
libLLVM.Test.CodeGen in '..\..\src\tests\libLLVM.Test.CodeGen.pas',
42-
libLLVM.LLD in '..\..\src\libLLVM.LLD.pas';
42+
libLLVM.LLD in '..\..\src\libLLVM.LLD.pas',
43+
libLLVM.Test.ObjectCompilation in '..\..\src\tests\libLLVM.Test.ObjectCompilation.pas';
4344

4445
begin
4546
RunTests();

examples/testbed/Testbed.dproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
<DCCReference Include="..\..\src\tests\libLLVM.Test.Variable.pas"/>
138138
<DCCReference Include="..\..\src\tests\libLLVM.Test.CodeGen.pas"/>
139139
<DCCReference Include="..\..\src\libLLVM.LLD.pas"/>
140+
<DCCReference Include="..\..\src\tests\libLLVM.Test.ObjectCompilation.pas"/>
140141
<BuildConfiguration Include="Base">
141142
<Key>Base</Key>
142143
</BuildConfiguration>

examples/testbed/UTestbed.pas

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ implementation
3737
libLLVM.Test.Comparison,
3838
libLLVM.Test.Bitwise,
3939
libLLVM.Test.BasicBlock,
40-
libLLVM.Test.Arithmetic;
40+
libLLVM.Test.Arithmetic,
41+
libLLVM.Test.ObjectCompilation;
4142

4243
procedure RunTests();
4344
var
@@ -48,7 +49,7 @@ procedure RunTests();
4849
TLLUtils.PrintLn('Running LLVM v%s', [TLLVM.GetLLVMVersionStr()]);
4950
TLLUtils.PrintLn();
5051

51-
LNum := 15;
52+
LNum := 22;
5253

5354
case LNum of
5455
01: TTestArithmetic.RunAllTests();
@@ -66,6 +67,15 @@ procedure RunTests();
6667
13: TTestValues.RunAllTests();
6768
14: TTestVariable.RunAllTests();
6869
15: TTestCodeGen.RunAllTests();
70+
71+
16: TTestObjectCompilation.TestSingleModuleCompilation();
72+
17: TTestObjectCompilation.TestBatchModuleCompilation();
73+
18: TTestObjectCompilation.TestOptimizationLevels();
74+
19: TTestObjectCompilation.TestFileExtensions();
75+
20: TTestObjectCompilation.TestOutputDirectories();
76+
21: TTestObjectCompilation.TestErrorConditions();
77+
22: TTestObjectCompilation.TestFileVerification();
78+
6979
else
7080
TLLUtils.Print('Invalid test number.');
7181
end;

src/libLLVM.pas

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,15 @@
5252
interface
5353

5454
uses
55+
WinApi.Windows,
5556
System.Types,
5657
System.SysUtils,
5758
System.AnsiStrings,
5859
System.TypInfo,
5960
System.Classes,
6061
System.Rtti,
6162
System.Math,
63+
System.IOUtils,
6264
System.Generics.Collections,
6365
libLLVM.API,
6466
libLLVM.Utils;
@@ -112,6 +114,14 @@ interface
112114
ccFastCall // LLVMX86FastcallCallConv
113115
);
114116

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+
115125
{ TLLParam }
116126
TLLParam = record
117127
ParamName: string;
@@ -164,6 +174,7 @@ TLLVM = class
164174
function GetBasicType(const ABasicType: TLLDataType; const AContext: LLVMContextRef): LLVMTypeRef;
165175
function GetLLVMCallingConv(const ACallingConv: TLLCallingConv): LLVMCallConv;
166176
function GetLLVMLinkage(const AVisibility: TLLVisibility): LLVMLinkage;
177+
function GetLLVMOptLevel(const AOptLevel: TLLOptimization): LLVMCodeGenOptLevel;
167178
{$HINTS OFF}
168179
function LLVMTypeToBasicType(ALLVMType: LLVMTypeRef): TLLDataType;
169180
{$HINTS ON}
@@ -203,6 +214,13 @@ TLLVM = class
203214
function ValidateModule(const AModuleId: string): Boolean;
204215
function GetRequiredLibraries(const AModuleId: string): TArray<string>;
205216

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+
206224
// Function declaration
207225
function BeginFunction(const AModuleId: string; const AFunctionName: string; const AReturnType: TLLDataType;
208226
const AParams: array of TLLParam; const AVisibility: TLLVisibility = vPublic;
@@ -488,6 +506,19 @@ class function TLLVM.GetLLVMVersionStr(): string;
488506
Result := Format('%d.%d.%d', [LMajor, LMinor, LPatch]);
489507
end;
490508

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+
491522
function TLLVM.SetTargetPlatform(const ATriple: string; const ADataLayout: string): TLLVM;
492523
begin
493524
FTargetTriple := ATriple;
@@ -563,6 +594,18 @@ function TLLVM.GetLLVMLinkage(const AVisibility: TLLVisibility): LLVMLinkage;
563594
end;
564595
end;
565596

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+
566609
function TLLVM.LLVMTypeToBasicType(ALLVMType: LLVMTypeRef): TLLDataType;
567610
var
568611
LKind: LLVMTypeKind;
@@ -839,6 +882,101 @@ function TLLVM.GetRequiredLibraries(const AModuleId: string): TArray<string>;
839882
SetLength(Result, 0);
840883
end;
841884

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+
842980
// Function declaration
843981
function TLLVM.BeginFunction(const AModuleId: string; const AFunctionName: string; const AReturnType: TLLDataType;
844982
const AParams: array of TLLParam; const AVisibility: TLLVisibility; const ACallingConv: TLLCallingConv;

0 commit comments

Comments
 (0)