Skip to content

Commit e6689c6

Browse files
committed
Fix es:LHS cast, swap expr, BC output
* Fixes LHS of assign casting * Simplify Swap expression * Enabled FMAD opt for arrays when possible
1 parent f694f44 commit e6689c6

File tree

8 files changed

+147
-63
lines changed

8 files changed

+147
-63
lines changed

compiler/xpr.bytecodeemitter.pas

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -710,10 +710,26 @@ procedure TBytecodeEmitter.Fuse();
710710
i, removals: Int32;
711711
begin
712712
removals := 0;
713-
for i:=0 to Bytecode.Code.Size-2 do
713+
for i:=0 to Bytecode.Code.Size-3 do
714714
begin
715-
if not (Bytecode.Code.Data[i+1].Args[0].BaseType in XprSimpleTypes) then
716-
Continue;
715+
//if not (Bytecode.Code.Data[i+1].Args[0].BaseType in XprSimpleTypes) then
716+
// Continue;
717+
718+
// sanity check:
719+
if InRange(Ord(Bytecode.Code.Data[i+0].Code), Ord(bcFMA_i32), Ord(bcFMA_i64)) and
720+
InRange(Ord(Bytecode.Code.Data[i+1].Code), Ord(bcDREF_32), Ord(bcDREF_64)) then
721+
begin
722+
if Bytecode.Code.Data[i].Args[3].Pos <> Bytecode.Code.Data[i+1].Args[1].Pos then
723+
continue;
724+
725+
// arrays are tricky, they will follow with INCLOCK, DONT TOUCH THESE CASES
726+
// this should have been cough by IsTemp, but guess not currently.
727+
if Bytecode.Code.Data[i+2].Code = bcINCLOCK then
728+
continue;
729+
end;
730+
731+
if not Intermediate.Code.Data[i].Args[3].IsTemporary then
732+
continue;
717733

718734
if (Bytecode.Code.Data[i+0].Code = bcFMA_i64) and (Bytecode.Code.Data[i+1].Code = bcDREF_64) then
719735
begin

compiler/xpr.express.pas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ destructor TExpress.Destroy;
196196
FBinder.Free;
197197
FTree.Free;
198198
FContext.Free;
199-
//FInterpreter.Free(FEmitter.Bytecode);
199+
FInterpreter.Free(FEmitter.Bytecode);
200200
inherited;
201201
end;
202202

compiler/xpr.parser.pas

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,6 @@ function TParser.ParsePrimary(): XTree_Node;
13131313
op:TToken;
13141314
name: string;
13151315
InitialPos: Int32;
1316-
Operand: XTree_Node;
13171316
prec: Int32;
13181317
begin
13191318
if IsInsesitive() then SkipNewline;

compiler/xpr.tree.pas

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,13 @@ function SameData(x: TInstructionData; y: TXprVar): Boolean;
601601
(x.IsTemporary = y.IsTemporary);
602602
end;
603603

604+
function TransferableData(x: TInstructionData; y: TXprVar): Boolean;
605+
begin
606+
Result := (x.Pos = y.MemPos) and (BaseIntType(x.BaseType) = BaseIntType(y.VarType.BaseType)) and
607+
(x.NestingLevel = y.NestingLevel) and (x.Reference = y.Reference) and
608+
(x.IsTemporary = y.IsTemporary);
609+
end;
610+
604611
function NodeArray(Arr: array of XTree_Node): XNodeArray;
605612
begin
606613
SetLength(Result, Length(Arr));
@@ -1601,7 +1608,7 @@ function XTree_TypeCast.CompileLValue(Dest: TXprVar): TXprVar;
16011608
end;
16021609

16031610
// Compile the underlying pointer expression.
1604-
SourceVar := Expression.Compile(NullResVar, []);
1611+
SourceVar := Expression.CompileLValue(Dest);
16051612

16061613
Result := SourceVar;
16071614
Result.VarType := Self.TargetType;
@@ -1612,7 +1619,6 @@ function XTree_TypeCast.CompileLValue(Dest: TXprVar): TXprVar;
16121619
// Class Declaration
16131620
//
16141621
constructor XTree_ClassDecl.Create(AName, AParentName: string; AFields, AMethods: XNodeArray; ACTX: TCompilerContext; DocPos: TDocPos);
1615-
var i: Int32;
16161622
begin
16171623
inherited Create(ACTX, DocPos);
16181624

@@ -3447,14 +3453,11 @@ function XTree_Invoke.CompileLValue(Dest: TXprVar): TXprVar;
34473453
if (Length(args) <> 1) then
34483454
ctx.RaiseExceptionFmt('Typecast expects exactly one argument, but got %d.', [Length(Args)], FDocPos);
34493455

3450-
if (not(args[0] is XTree_Identifier)) or (not(Method is XTree_Identifier)) then
3451-
ctx.RaiseException('Functions can not be written to', FDocPos);
3452-
3453-
vType := ctx.GetType(XTree_Identifier(Self.Method).Name);
3454-
if vType <> nil then
3456+
if (Length(Args) = 1) and (SelfExpr = nil) and (Method is XTree_Identifier) then
34553457
begin
3456-
if Length(Args) <> 1 then
3457-
ctx.RaiseExceptionFmt('Typecast expects exactly one argument, but got %d.', [Length(Args)], FDocPos);
3458+
vType := ctx.GetType(XTree_Identifier(Self.Method).Name);
3459+
if vType = nil then
3460+
ctx.RaiseException('Functions can not be written to', FDocPos);
34583461

34593462
with XTree_TypeCast.Create(vType, Self.Args[0], FContext, FDocPos) do
34603463
try
@@ -3463,7 +3466,7 @@ function XTree_Invoke.CompileLValue(Dest: TXprVar): TXprVar;
34633466
Free;
34643467
end;
34653468
end else
3466-
ctx.RaiseException(eUnexpected, FDocPos);
3469+
ctx.RaiseException('Functions can not be written to', FDocPos);
34673470
end;
34683471

34693472

@@ -4969,7 +4972,7 @@ function XTree_Assign.Compile(Dest: TXprVar; Flags: TCompilerFlags): TXprVar;
49694972
case last_instr_ptr^.Code of
49704973
icADD..icSAR:
49714974
begin
4972-
if SameData(last_instr_ptr^.Args[2], RightVar) then
4975+
if TransferableData(last_instr_ptr^.Args[2], RightVar) then
49734976
begin
49744977
last_instr_ptr^.Args[2].Addr := LeftVar.Addr;
49754978
Exit(True);
@@ -4978,7 +4981,7 @@ function XTree_Assign.Compile(Dest: TXprVar; Flags: TCompilerFlags): TXprVar;
49784981

49794982
icDREF:
49804983
begin
4981-
if SameData(last_instr_ptr^.Args[0], RightVar) then
4984+
if TransferableData(last_instr_ptr^.Args[0], RightVar) then
49824985
begin
49834986
last_instr_ptr^.Args[0].Addr := LeftVar.Addr;
49844987
Exit(True);
@@ -5036,25 +5039,45 @@ function XTree_Assign.Compile(Dest: TXprVar; Flags: TCompilerFlags): TXprVar;
50365039
TargetNode: XTree_Node;
50375040
SourceFieldNode: XTree_Field;
50385041
AssignNode: XTree_Assign;
5039-
TempFieldNames: XStringList;
5040-
TempTypeList: XTypeList;
5042+
RightHandSideValues: array of TXprVar;
5043+
InitializerList: XTree_InitializerList;
50415044
begin
50425045
// Compile RHS expression once to a temp!
50435046

50445047
// special case of (a,b) := [b,a]
50455048
if RHS_Node is XTree_InitializerList then
50465049
begin
5047-
TempFieldNames.Init([]);
5048-
TempTypeList.Init([]);
5049-
for i:=0 to High(PatternNode.Targets) do
5050+
InitializerList := RHS_Node as XTree_InitializerList;
5051+
5052+
// Sanity check: the number of items must match.
5053+
if Length(PatternNode.Targets) <> Length(InitializerList.Items) then
5054+
ctx.RaiseExceptionFmt('The number of variables in the pattern (%d) does not match the number of values in the initializer list (%d).',
5055+
[Length(PatternNode.Targets), Length(InitializerList.Items)], PatternNode.FDocPos);
5056+
5057+
// Evaluate all expressions on the right-hand side and store their
5058+
// results in **tempvars** before any assignment happens.
5059+
RightHandSideValues := [];
5060+
SetLength(RightHandSideValues, Length(InitializerList.Items));
5061+
for i := 0 to High(InitializerList.Items) do
5062+
RightHandSideValues[i] := InitializerList.Items[i].Compile(NullResVar, Flags);
5063+
5064+
// Now we can assign them to the LHS targets!
5065+
for i := 0 to High(PatternNode.Targets) do
50505066
begin
5051-
TempFieldNames.Add('!'+i.ToString());
5052-
TempTypeList.Add(PatternNode.Targets[i].ResType());
5067+
AssignNode := XTree_Assign.Create(
5068+
op_Asgn,
5069+
PatternNode.Targets[i],
5070+
XTree_VarStub.Create(RightHandSideValues[i], ctx, RHS_Node.FDocPos),
5071+
ctx,
5072+
FDocPos
5073+
);
5074+
try
5075+
AssignNode.Compile(NullResVar, Flags);
5076+
finally
5077+
AssignNode.Free;
5078+
end;
50535079
end;
5054-
5055-
RecType := XType_Record.Create(TempFieldNames, TempTypeList);
5056-
ctx.AddManagedType(RecType);
5057-
RHS_Node.FResType := RecType;
5080+
Exit; // We are done with this path.
50585081
end;
50595082

50605083

examples/SciMark.xpr

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ const PI := 3.14159265358979323846
2929
type TFloatArray = array of Float
3030
type TIntArray = array of Int
3131
type T2DFloatArray = array of TFloatArray
32+
type P2DFloatArray = ^T2DFloatArray
33+
type PDouble = ^Double;
3234

3335
// -----------------------------
3436
// Stopwatch (from Stopwatch.pas) - ERROR XXX **bugged records??**
@@ -335,9 +337,11 @@ end
335337

336338
func LU_factor(M, N: Int; a: T2DFloatArray; pivot: TIntArray): Int
337339
var minmn := Min(M, N)
340+
338341
for (var j := 0; j < minmn; j += 1) do
339342
var jp := j
340343
var t := Abs(a[j][j])
344+
341345
for (var i := j + 1; i < M; i += 1) do
342346
var ab := Abs(a[i][j])
343347
if (ab > t) then
@@ -350,10 +354,13 @@ func LU_factor(M, N: Int; a: T2DFloatArray; pivot: TIntArray): Int
350354
if (a[jp][j] = 0.0)
351355
return 1 // factorization failed
352356

353-
if (jp != j) then // XXX (a,b) := [b,a] broken
354-
var ta := A[j];
355-
A[j] := A[jp];
356-
A[jp] := ta;
357+
if (jp != j) then
358+
// NOTE: (a,b) := [b,a] --- causes release of arrays:
359+
// > t1{noref+} := a, t2{noref+} := b
360+
// > a{-ref} := t1 { we just free'd a XXX }
361+
// > b{-ref} := t2 { empty data }
362+
363+
(Pointer(a[jp]),Pointer(a[j])) := [Pointer(a[j]),Pointer(a[jp])]
357364
end
358365

359366
if (j < M - 1) then
@@ -365,15 +372,16 @@ func LU_factor(M, N: Int; a: T2DFloatArray; pivot: TIntArray): Int
365372

366373
if (j < minmn - 1) then
367374
for (var ii := j + 1; ii < M; ii += 1) do
368-
var aii := a[ii]
369-
var aj := a[j]
375+
var aii := PDouble(a[ii]) // no refcount & collect
376+
var aj := PDouble(a[j])
370377
var aiiJ := aii[j]
371378
for (var jj := j + 1; jj < N; jj += 1) do
372379
aii[jj] -= aiiJ * aj[jj]
373380
end
374381
end
375382
end
376383
end
384+
377385
return 0
378386
end
379387

examples/cluster.xpr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func SplitTPA(Points: TPointArray DistX, DistY: Int): T2DPointArray
1717

1818
var LastIndex := Points.High()
1919
var ProcCount := 0
20-
(*
20+
2121
while (LastIndex - ProcCount >= 0) do
2222
var Current := [Points[0]]
2323
Points[0] := Points[LastIndex - ProcCount]
@@ -49,7 +49,6 @@ func SplitTPA(Points: TPointArray DistX, DistY: Int): T2DPointArray
4949
Result.SetLen(Result.Len()+1)
5050
Result[Result.High()] := Current
5151
end
52-
*)
5352
end
5453

5554
func GeneratePoints(N: Int): TPointArray

main.pas

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,39 +24,38 @@ procedure RunScript(const AFileName: string);
2424
WriteLn('Program use so far: ', (GetFPCHeapStatus().CurrHeapUsed - StartHeapUsed) div 1024,' KB');
2525

2626
Script := TExpress.Create;
27-
try
28-
// --- COMPILATION ---
29-
WriteFancy('Compiling...');
30-
Script.CompileFile(AFileName);
3127

32-
WriteFancy(Script.BC.ToString(True));
28+
// --- COMPILATION ---
29+
WriteFancy('Compiling...');
30+
Script.CompileFile(AFileName);
3331

34-
// After compiling, read the stats from the properties.
35-
WriteFancy('Parsed source in %.3f ms', [Script.ParseTimeMs]);
36-
WriteFancy('Compiled AST in %.3f ms', [Script.ASTCompileTimeMs]);
37-
WriteFancy('Emitted Bytecode in %.3f ms', [Script.BytecodeEmitTimeMs]);
38-
WriteFancy('Total compile time: %.3f ms', [Script.TotalCompileTimeMs]);
39-
WriteFancy('Memory used for compilation: %.4f MB', [Script.CompileMemoryUsedMb]);
40-
WriteLn;
32+
WriteFancy(Script.BC.ToString(True));
4133

42-
// --- EXECUTION ---
43-
WriteLn('Executing...');
44-
exec_t := MarkTime();
34+
// After compiling, read the stats from the properties.
35+
WriteFancy('Parsed source in %.3f ms', [Script.ParseTimeMs]);
36+
WriteFancy('Compiled AST in %.3f ms', [Script.ASTCompileTimeMs]);
37+
WriteFancy('Emitted Bytecode in %.3f ms', [Script.BytecodeEmitTimeMs]);
38+
WriteFancy('Total compile time: %.3f ms', [Script.TotalCompileTimeMs]);
39+
WriteFancy('Memory used for compilation: %.4f MB', [Script.CompileMemoryUsedMb]);
40+
WriteLn;
4541

46-
Script.Run();
42+
// --- EXECUTION ---
43+
WriteLn('Executing...');
44+
exec_t := MarkTime();
4745

48-
exec_t := MarkTime() - exec_t;
49-
WriteFancy('Executed in %.3f ms', [exec_t]);
50-
WriteFancy('Memory spilled in execution: %d bytes', [Script.MemorySpilled]);
46+
Script.Run();
5147

52-
// --- Example of getting a result back ---
53-
resultVar := Script.GetVar('Result');
54-
if not VarIsNull(resultVar) then
55-
WriteFancy('Script returned ''Result'': %s', [string(resultVar)]);
48+
exec_t := MarkTime() - exec_t;
49+
WriteFancy('Executed in %.3f ms', [exec_t]);
50+
WriteFancy('Memory spilled in execution: %d bytes', [Script.MemorySpilled]);
51+
52+
// --- Example of getting a result back ---
53+
resultVar := Script.GetVar('Result');
54+
if not VarIsNull(resultVar) then
55+
WriteFancy('Script returned ''Result'': %s', [string(resultVar)]);
56+
57+
Script.Free;
5658

57-
finally
58-
Script.Free;
59-
end;
6059

6160
WriteLn('Program leaked: ', (GetFPCHeapStatus().CurrHeapUsed - StartHeapUsed) div 1024,' KB');
6261
end;
@@ -70,7 +69,7 @@ procedure RunScript(const AFileName: string);
7069
WriteFancy('Express Host ' + {$I %Date%} + ' ' + {$I %Time%});
7170
WriteFancy('-----------------------------------');
7271

73-
fileName := 'examples/cluster.xpr';
72+
fileName := 'tests/listexpr.xpr';
7473
if ParamCount > 0 then
7574
fileName := ParamStr(1);
7675

tests/listexpr.xpr

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
type TIntArray = array of int
2+
type TIntMatrix = array of TIntArray;
3+
4+
var a: array of int;
5+
var j:Int = 0
6+
var i:Int = 1
7+
8+
a := [i,2,3,4]
9+
10+
print a[0]
11+
print a[1]
12+
print a[2]
13+
print a[3]
14+
print '--------------'
15+
16+
(a[i],a[j]) := [a[j],a[i]]
17+
18+
19+
print a[0]
20+
print a[1]
21+
print a[2]
22+
print a[3]
23+
24+
// ^ works as expected.. N-d is where it fails:
25+
26+
27+
var a,b: TIntArray;
28+
var x: TIntMatrix;
29+
30+
a := [1,2,3,4]
31+
b := [4,5,6,7]
32+
33+
x := [a,b]
34+
35+
print x[0][0]
36+
print x[1][0]
37+
38+
(Pointer(x[0]),Pointer(x[1])) := [Pointer(x[1]),Pointer(x[0])]
39+
print x[0][0]
40+
print x[1][0]

0 commit comments

Comments
 (0)