From 40d9b1108ae89d3e40acc3fac0bb15d503fb1d9d Mon Sep 17 00:00:00 2001 From: florian Date: Sat, 26 Sep 2020 15:35:20 +0000 Subject: [PATCH 01/13] * add VUString branch to tvardata, resolves #37651 git-svn-id: trunk@46957 - --- rtl/inc/varianth.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtl/inc/varianth.inc b/rtl/inc/varianth.inc index 66f0406bc6..cc05df8eb9 100644 --- a/rtl/inc/varianth.inc +++ b/rtl/inc/varianth.inc @@ -113,6 +113,7 @@ type varerror : (verror : hresult); varboolean : (vboolean : wordbool); varunknown : (vunknown : pointer); + varustring : (vustring : pointer); // vardecimal : ( : ); varshortint : (vshortint : shortint); varbyte : (vbyte : byte); From aa8fdabe1f0ed4157fef8c25c4a4ef688877a843 Mon Sep 17 00:00:00 2001 From: florian Date: Sat, 26 Sep 2020 15:44:37 +0000 Subject: [PATCH 02/13] * xtensa-freertos: patch by Alfred for better tool search, resolves #37308 git-svn-id: trunk@46958 - --- compiler/systems/t_freertos.pas | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/compiler/systems/t_freertos.pas b/compiler/systems/t_freertos.pas index 05b172ee49..af189fb29b 100644 --- a/compiler/systems/t_freertos.pas +++ b/compiler/systems/t_freertos.pas @@ -1115,13 +1115,13 @@ begin writeln(t,' "COMPONENT_KCONFIGS_PROJBUILD": "Kconfig.projbuild",'); writeln(t,' "IDF_CMAKE": "y",'); writeln(t,' "IDF_TARGET": "esp32",'); - writeln(t,' "IDF_PATH": "'+idfpath+'",'); + writeln(t,' "IDF_PATH": "'+TargetFixPath(idfpath,false)+'",'); writeln(t,' "COMPONENT_KCONFIGS_SOURCE_FILE": "kconfigs.in",'); writeln(t,' "COMPONENT_KCONFIGS_PROJBUILD_SOURCE_FILE": "kconfigs_projbuild.in"'); end else begin - writeln(t,' "IDF_PATH": "'+idfpath+'",'); + writeln(t,' "IDF_PATH": "'+TargetFixPath(idfpath,false)+'",'); writeln(t,' "IDF_TARGET": "esp8266",'); writeln(t,' "IDF_CMAKE": "n"'); end; @@ -1161,9 +1161,13 @@ begin success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,true); { generate linker maps } - binstr:='$IDF_PATH/tools/ldgen/ldgen.py'; + binstr:='python'; + if source_info.exeext<>'' then + binstr:=binstr+source_info.exeext; + S:=FindUtil(utilsprefix+'objdump'); if (current_settings.controllertype = ct_esp32) then - cmdstr:='--config sdkconfig '+ + cmdstr:='$IDF_PATH/tools/ldgen/ldgen.py '+ + '--config sdkconfig '+ '--fragments $IDF_PATH/components/xtensa/linker.lf $IDF_PATH/components/soc/linker.lf $IDF_PATH/components/esp_event/linker.lf '+ '$IDF_PATH/components/spi_flash/linker.lf $IDF_PATH/components/esp_wifi/linker.lf $IDF_PATH/components/lwip/linker.lf '+ '$IDF_PATH/components/heap/linker.lf $IDF_PATH/components/esp_ringbuf/linker.lf $IDF_PATH/components/espcoredump/linker.lf $IDF_PATH/components/esp32/linker.lf '+ @@ -1174,9 +1178,10 @@ begin '--kconfig $IDF_PATH/Kconfig '+ '--env-file config.env '+ '--libraries-file ldgen_libraries '+ - '--objdump xtensa-esp32-elf-objdump' + '--objdump '+S else - cmdstr:='--config sdkconfig '+ + cmdstr:='$IDF_PATH/tools/ldgen/ldgen.py '+ + '--config sdkconfig '+ '--fragments $IDF_PATH/components/esp8266/ld/esp8266_fragments.lf '+ '$IDF_PATH/components/esp8266/ld/esp8266_bss_fragments.lf $IDF_PATH/components/esp8266/linker.lf '+ '$IDF_PATH/components/freertos/linker.lf $IDF_PATH/components/log/linker.lf '+ @@ -1191,9 +1196,8 @@ begin '--kconfig $IDF_PATH/Kconfig '+ '--env-file config.env '+ '--libraries-file ldgen_libraries '+ - '--objdump xtensa-lx106-elf-objdump'; + '--objdump '+S; - Replace(binstr,'$IDF_PATH',idfpath); Replace(cmdstr,'$IDF_PATH',idfpath); if success and not(cs_link_nolink in current_settings.globalswitches) then success:=DoExec(binstr,cmdstr,true,false); @@ -1262,10 +1266,13 @@ begin {$ifdef XTENSA} if success then begin - binstr:=idfpath+'/components/esptool_py/esptool/esptool.py'; + binstr:='python'; + if source_info.exeext<>'' then + binstr:=binstr+source_info.exeext; + cmdstr:=idfpath+'/components/esptool_py/esptool/esptool.py '; if (current_settings.controllertype = ct_esp32) then begin - success:=DoExec(binstr,'--chip esp32 elf2image --flash_mode dio --flash_freq 40m '+ + success:=DoExec(binstr,cmdstr+'--chip esp32 elf2image --flash_mode dio --flash_freq 40m '+ '--flash_size '+tostr(embedded_controllers[current_settings.controllertype].flashsize div (1024*1024))+'MB '+ '--elf-sha256-offset 0xb0 '+ '-o '+maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.bin')))+' '+ @@ -1274,7 +1281,7 @@ begin end else if (current_settings.controllertype = ct_esp8266) then begin - success:=DoExec(binstr,'--chip esp8266 elf2image --flash_mode dout --flash_freq 40m '+ + success:=DoExec(binstr,cmdstr+'--chip esp8266 elf2image --flash_mode dout --flash_freq 40m '+ '--flash_size '+tostr(embedded_controllers[current_settings.controllertype].flashsize div (1024*1024))+'MB '+ '--version=3 '+ '-o '+maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.bin')))+' '+ From ffef243908b12907c42577c5129820251ca82a47 Mon Sep 17 00:00:00 2001 From: Mattias Gaertner Date: Sat, 26 Sep 2020 16:37:27 +0000 Subject: [PATCH 03/13] pastojs: ShortRefGlobals: local var for TEnumType git-svn-id: trunk@46959 - --- packages/pastojs/src/fppas2js.pp | 43 +++++++++++-- packages/pastojs/tests/tcoptimizations.pas | 75 ++++++++++++++++++++++ 2 files changed, 113 insertions(+), 5 deletions(-) diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp index 80bcdfd046..fc5fdc25ca 100644 --- a/packages/pastojs/src/fppas2js.pp +++ b/packages/pastojs/src/fppas2js.pp @@ -15278,6 +15278,8 @@ function TPasToJSConverter.ConvertEnumType(El: TPasEnumType; // minvalue: 0, // maxvalue: 1 // }); +// coShortRefGlobals: +// var $lt = this.TMyEnum ... var ObjectContect: TObjectContext; i: Integer; @@ -15285,7 +15287,7 @@ var ParentObj, Obj, TIObj: TJSObjectLiteral; ObjLit, TIProp: TJSObjectLiteralElement; AssignSt: TJSSimpleAssignStatement; - JSName: TJSString; + JSName: string; Call: TJSCallExpression; List: TJSStatementList; ok: Boolean; @@ -15293,6 +15295,7 @@ var Src: TJSSourceElements; ProcScope: TPas2JSProcedureScope; VarSt: TJSVariableStatement; + GlobalCtx: TConvertContext; begin Result:=nil; for i:=0 to El.Values.Count-1 do @@ -15322,11 +15325,14 @@ begin else if El.Parent is TProcedureBody then begin // add 'var TypeName = {}' - VarSt:=CreateVarStatement(TransformElToJSName(El,AContext),Obj,El); + JSName:=TransformElToJSName(El,AContext); + VarSt:=CreateVarStatement(JSName,Obj,El); if AContext.JSElement is TJSSourceElements then begin Src:=TJSSourceElements(AContext.JSElement); AddToSourceElements(Src,VarSt); // keep Result=nil + if AContext is TFunctionContext then + TFunctionContext(AContext).AddLocalVar(JSName,El,cvkGlobal,false); end else Result:=VarSt; @@ -15338,20 +15344,47 @@ begin AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext); AssignSt.Expr:=Obj; Result:=AssignSt; + if (coShortRefGlobals in Options) and (AContext is TFunctionContext) then + begin + GlobalCtx:=AContext; + while (GlobalCtx.PasElement is TPasMembersType) do + GlobalCtx:=GlobalCtx.Parent; + if (GlobalCtx<>AContext) and (GlobalCtx is TFunctionContext) then + begin + // add to GlobalCtx: var $lt = {} + // add to local context: this.TypeName = $lt + if not (GlobalCtx.JSElement is TJSSourceElements) then + RaiseNotSupported(El,AContext,20200926181516,GetObjName(GlobalCtx.JSElement)); + Src:=TJSSourceElements(GlobalCtx.JSElement); + JSName:=TFunctionContext(AContext).CreateLocalIdentifier(GetBIName(pbivnLocalTypeRef)); + AssignSt.Expr:=CreatePrimitiveDotExpr(JSName,El); + + VarSt:=CreateVarStatement(JSName,Obj,El); + AddToSourceElements(Src,VarSt); + TFunctionContext(GlobalCtx).AddLocalVar(JSName,El,cvkGlobal,false); + end + else + begin + // var $lt = this.TypeName = {} + JSName:=TFunctionContext(AContext).CreateLocalIdentifier(GetBIName(pbivnLocalTypeRef)); + TFunctionContext(AContext).AddLocalVar(JSName,El,cvkGlobal,false); + Result:=CreateVarStatement(JSName,AssignSt,El); + end; + end; end; ObjectContect:=TObjectContext.Create(El,Obj,AContext); for i:=0 to El.Values.Count-1 do begin EnumValue:=TPasEnumValue(El.Values[i]); - JSName:=TJSString(TransformElToJSName(EnumValue,AContext)); + JSName:=TransformElToJSName(EnumValue,AContext); // add "0":"value" ObjLit:=Obj.Elements.AddElement; ObjLit.Name:=TJSString(IntToStr(i)); - ObjLit.Expr:=CreateLiteralJSString(El,JSName); + ObjLit.Expr:=CreateLiteralJSString(El,TJSString(JSName)); // add value:0 ObjLit:=Obj.Elements.AddElement; - ObjLit.Name:=JSName; + ObjLit.Name:=TJSString(JSName); ObjLit.Expr:=CreateLiteralNumber(El,i); end; diff --git a/packages/pastojs/tests/tcoptimizations.pas b/packages/pastojs/tests/tcoptimizations.pas index 1c87d5dc9b..d23c23680c 100644 --- a/packages/pastojs/tests/tcoptimizations.pas +++ b/packages/pastojs/tests/tcoptimizations.pas @@ -61,6 +61,7 @@ type procedure TestOptShortRefGlobals_Unit_FromIntfImpl_ToIntfImpl; procedure TestOptShortRefGlobals_Property; procedure TestOptShortRefGlobals_GenericFunction; + procedure TestOptShortRefGlobals_SameUnit_EnumType; // Whole Program Optimization procedure TestWPO_OmitLocalVar; @@ -490,6 +491,80 @@ begin ''])); end; +procedure TTestOptimizations.TestOptShortRefGlobals_SameUnit_EnumType; +begin + StartUnit(true,[supTObject]); + Add([ + '{$optimization JSShortRefGlobals}', + 'interface', + 'type', + ' TEnum = (red,blue);', + ' TBird = class', + ' type', + ' TFlag = (big,small);', + ' procedure Fly;', + ' end;', + 'var f: TBird.TFlag;', + 'procedure Run;', + 'implementation', + 'procedure TBird.Fly;', + 'begin', + ' f:=small;', + 'end;', + 'procedure Run;', + 'type TSub = (left,right);', + 'var e: TEnum;', + ' s: TSub;', + 'begin', + ' e:=red;', + ' s:=right;', + ' f:=big;', + 'end;', + '']); + ConvertUnit; + CheckSource('TestOptShortRefGlobals_SameUnit_EnumType', + LinesToStr([ + 'var $lm = pas.system;', + 'var $lt1 = $lm.TObject;', + 'var $lt = this.TEnum = {', + ' "0": "red",', + ' red: 0,', + ' "1": "blue",', + ' blue: 1', + '};', + 'var $lt2 = {', + ' "0": "big",', + ' big: 0,', + ' "1": "small",', + ' small: 1', + ' };', + 'rtl.createClass(this, "TBird", $lt1, function () {', + ' this.TFlag = $lt2;', + ' this.Fly = function () {', + ' $mod.f = $lt2.small;', + ' };', + '});', + 'this.f = 0;', + 'var TSub = {', + ' "0": "left",', + ' left: 0,', + ' "1": "right",', + ' right: 1', + '};', + 'this.Run = function () {', + ' var e = 0;', + ' var s = 0;', + ' e = $lt.red;', + ' s = TSub.right;', + ' $mod.f = $lt2.big;', + '};', + '']), + LinesToStr([ + '']), + LinesToStr([ + ''])); +end; + procedure TTestOptimizations.TestWPO_OmitLocalVar; begin StartProgram(false); From 112f8a41add94fb12a75636a4b45a155725d9b1e Mon Sep 17 00:00:00 2001 From: florian Date: Sat, 26 Sep 2020 20:12:27 +0000 Subject: [PATCH 04/13] * Xtensa: set is_jmp flag so branch optimization works git-svn-id: trunk@46960 - --- compiler/aoptobj.pas | 9 +++++++-- compiler/xtensa/cgcpu.pas | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/compiler/aoptobj.pas b/compiler/aoptobj.pas index d97ebb45d9..4b635e12c9 100644 --- a/compiler/aoptobj.pas +++ b/compiler/aoptobj.pas @@ -464,8 +464,8 @@ Unit AoptObj; function JumpTargetOp(ai: taicpu): poper; inline; begin -{$if defined(MIPS) or defined(riscv64) or defined(riscv32)} - { MIPS or RiscV branches can have 1,2 or 3 operands, target label is the last one. } +{$if defined(MIPS) or defined(riscv64) or defined(riscv32) or defined(xtensa)} + { MIPS, Xtensa or RiscV branches can have 1,2 or 3 operands, target label is the last one. } result:=ai.oper[ai.ops-1]; {$elseif defined(SPARC64)} if ai.ops=2 then @@ -1644,6 +1644,11 @@ Unit AoptObj; p.loadreg(0, NR_X0); p.ops:=2; {$endif} +{$ifdef xtensa} + p.opcode := aopt_uncondjmp; + p.loadoper(0, p.oper[p.ops-1]^); + p.ops:=1; +{$endif} {$endif not avr} {$ifdef mips} { MIPS conditional jump instructions also conntain register diff --git a/compiler/xtensa/cgcpu.pas b/compiler/xtensa/cgcpu.pas index 9de0f6c4fc..8a8f3fe126 100644 --- a/compiler/xtensa/cgcpu.pas +++ b/compiler/xtensa/cgcpu.pas @@ -621,6 +621,7 @@ implementation begin instr:=taicpu.op_reg_sym(A_B,f.register,l); instr.condition:=flags_to_cond(f.flag); + instr.is_jmp:=true; list.concat(instr); end else @@ -905,6 +906,7 @@ implementation end; instr:=taicpu.op_reg_sym(A_B,reg,l); instr.condition:=op; + instr.is_jmp:=true; list.concat(instr); end else if is_b4const(a) and @@ -921,6 +923,7 @@ implementation instr:=taicpu.op_reg_const_sym(A_B,reg,a,l); instr.condition:=op; + instr.is_jmp:=true; list.concat(instr); end else if is_b4constu(a) and @@ -935,6 +938,7 @@ implementation instr:=taicpu.op_reg_const_sym(A_B,reg,a,l); instr.condition:=op; + instr.is_jmp:=true; list.concat(instr); end else @@ -958,6 +962,7 @@ implementation instr:=taicpu.op_reg_reg_sym(A_B,reg2,reg1,l); instr.condition:=TOpCmp2AsmCond[cmp_op]; + instr.is_jmp:=true; list.concat(instr); end; From 4ced513363c3a2a387b144a2b5639cc331957b02 Mon Sep 17 00:00:00 2001 From: florian Date: Sat, 26 Sep 2020 20:12:28 +0000 Subject: [PATCH 05/13] * xtensa-freertos: run python helpers only on non unix by directly calling python git-svn-id: trunk@46961 - --- compiler/systems/t_freertos.pas | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/systems/t_freertos.pas b/compiler/systems/t_freertos.pas index af189fb29b..d3e36d923a 100644 --- a/compiler/systems/t_freertos.pas +++ b/compiler/systems/t_freertos.pas @@ -1161,12 +1161,16 @@ begin success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,true); { generate linker maps } +{$ifdef UNIX} + binstr:=TargetFixPath(idfpath,false)+'/tools/ldgen/ldgen.py'; +{$else} binstr:='python'; +{$endif UNIX} if source_info.exeext<>'' then binstr:=binstr+source_info.exeext; S:=FindUtil(utilsprefix+'objdump'); if (current_settings.controllertype = ct_esp32) then - cmdstr:='$IDF_PATH/tools/ldgen/ldgen.py '+ + cmdstr:={$ifndef UNIX}'$IDF_PATH/tools/ldgen/ldgen.py '+{$endif UNIX} '--config sdkconfig '+ '--fragments $IDF_PATH/components/xtensa/linker.lf $IDF_PATH/components/soc/linker.lf $IDF_PATH/components/esp_event/linker.lf '+ '$IDF_PATH/components/spi_flash/linker.lf $IDF_PATH/components/esp_wifi/linker.lf $IDF_PATH/components/lwip/linker.lf '+ @@ -1180,7 +1184,7 @@ begin '--libraries-file ldgen_libraries '+ '--objdump '+S else - cmdstr:='$IDF_PATH/tools/ldgen/ldgen.py '+ + cmdstr:={$ifndef UNIX}'$IDF_PATH/tools/ldgen/ldgen.py '+{$endif UNIX} '--config sdkconfig '+ '--fragments $IDF_PATH/components/esp8266/ld/esp8266_fragments.lf '+ '$IDF_PATH/components/esp8266/ld/esp8266_bss_fragments.lf $IDF_PATH/components/esp8266/linker.lf '+ @@ -1266,10 +1270,15 @@ begin {$ifdef XTENSA} if success then begin +{$ifdef UNIX} + binstr:=TargetFixPath(idfpath,false)+'/components/esptool_py/esptool/esptool.py'; + cmdstr:=''; +{$else} binstr:='python'; + cmdstr:=idfpath+'/components/esptool_py/esptool/esptool.py '; +{$endif UNIX} if source_info.exeext<>'' then binstr:=binstr+source_info.exeext; - cmdstr:=idfpath+'/components/esptool_py/esptool/esptool.py '; if (current_settings.controllertype = ct_esp32) then begin success:=DoExec(binstr,cmdstr+'--chip esp32 elf2image --flash_mode dio --flash_freq 40m '+ From 1c370ccde1767aadb4d89aa9eb48b4ba68a39733 Mon Sep 17 00:00:00 2001 From: florian Date: Sat, 26 Sep 2020 20:12:29 +0000 Subject: [PATCH 06/13] + xtensa: make use of float.s instruction git-svn-id: trunk@46962 - --- compiler/xtensa/ncpucnv.pas | 44 +++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/compiler/xtensa/ncpucnv.pas b/compiler/xtensa/ncpucnv.pas index b491723f9f..6c065fecda 100644 --- a/compiler/xtensa/ncpucnv.pas +++ b/compiler/xtensa/ncpucnv.pas @@ -33,6 +33,8 @@ interface protected function first_real_to_real: tnode;override; procedure second_int_to_bool;override; + procedure second_int_to_real;override; + function first_int_to_real: tnode;override; end; implementation @@ -67,7 +69,7 @@ implementation left:=nil; end; else - internalerror(200610151); + internalerror(2020092603); end; s64real: case tfloatdef(resultdef).floattype of @@ -80,10 +82,10 @@ implementation left:=nil; end; else - internalerror(200610152); + internalerror(2020092602); end; else - internalerror(200610153); + internalerror(2020092601); end; left:=nil; firstpass(result); @@ -94,7 +96,6 @@ implementation end; - procedure tcputypeconvnode.second_int_to_bool; var hreg1, onereg: tregister; @@ -187,6 +188,41 @@ implementation end; + function tcputypeconvnode.first_int_to_real: tnode; + var + fname: string[19]; + begin + if (cs_fp_emulation in current_settings.moduleswitches) or + (current_settings.fputype=fpu_soft) or + not(FPUXTENSA_SINGLE in fpu_capabilities[current_settings.fputype]) or + ((is_double(resultdef)) and not(FPUXTENSA_DOUBLE in fpu_capabilities[current_settings.fputype])) or + is_64bitint(left.resultdef) or + is_currency(left.resultdef) or + (is_32bit(left.resultdef) and not(is_signed(left.resultdef))) then + result:=inherited first_int_to_real + else + begin + { other integers are supposed to be 32 bit } + inserttypeconv(left,s32inttype); + firstpass(left); + result:=nil; + expectloc:=LOC_FPUREGISTER; + end; + end; + + + procedure tcputypeconvnode.second_int_to_real; + var + ai: taicpu; + begin + location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef)); + location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size); + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,s32inttype,true); + ai:=taicpu.op_reg_reg_const(A_FLOAT,location.register,left.location.register,0); + ai.oppostfix:=PF_S; + current_asmdata.CurrAsmList.concat(ai); + end; + begin ctypeconvnode:=tcputypeconvnode; end. From 7f53d04ffdc6b44800ac1caf9276116754975ef1 Mon Sep 17 00:00:00 2001 From: florian Date: Sat, 26 Sep 2020 22:03:13 +0000 Subject: [PATCH 07/13] + xtensa: make use of nsau to implement Bsr* git-svn-id: trunk@46963 - --- compiler/options.pas | 10 ++++++++++ compiler/xtensa/cgcpu.pas | 24 ++++++++++++++++++++++++ compiler/xtensa/cpuinfo.pas | 3 ++- rtl/inc/systemh.inc | 2 +- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/compiler/options.pas b/compiler/options.pas index 00745d25ca..dfc0930f1c 100644 --- a/compiler/options.pas +++ b/compiler/options.pas @@ -4619,6 +4619,16 @@ begin end; {$endif} +{$if defined(xtensa)} + { it is determined during system unit compilation if nsau is used for bsr or not, + this is not perfect but the current implementation bsf/bsr does not allow another + solution } + if CPUXTENSA_HAS_NSAx in cpu_capabilities[init_settings.cputype] then + begin + def_system_macro('FPC_HAS_INTERNAL_BSR'); + end; +{$endif} + {$if defined(powerpc64)} { on sysv targets, default to elfv2 for little endian and to elfv1 for big endian (unless specified otherwise). As the gcc man page says: diff --git a/compiler/xtensa/cgcpu.pas b/compiler/xtensa/cgcpu.pas index 8a8f3fe126..7c1828ee17 100644 --- a/compiler/xtensa/cgcpu.pas +++ b/compiler/xtensa/cgcpu.pas @@ -69,6 +69,8 @@ interface procedure a_cmp_reg_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);override; procedure a_jmp_always(list: TAsmList; l: TAsmLabel);override; + procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: TCGSize; src, dst: TRegister);override; + procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);override; procedure g_concatcopy(list : TAsmList; const source,dest : treference; len : tcgint);override; @@ -1270,6 +1272,28 @@ implementation end; + procedure tcgcpu.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: TCGSize; src, dst: TRegister); + var + ai: taicpu; + tmpreg: TRegister; + begin + if reverse then + begin + list.Concat(taicpu.op_reg_reg(A_NSAU,dst,src)); + tmpreg:=getintregister(list,OS_INT); + a_load_const_reg(list,OS_INT,31,tmpreg); + a_op_reg_reg_reg(list,OP_SUB,OS_INT,dst,tmpreg,dst); + tmpreg:=getintregister(list,OS_INT); + a_load_const_reg(list,OS_INT,255,tmpreg); + ai:=taicpu.op_reg_reg_reg(A_MOV,dst,tmpreg,src); + ai.condition:=C_EQZ; + list.Concat(ai); + end + else + Internalerror(2020092604); + end; + + procedure tcg64fxtensa.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64); var instr: taicpu; diff --git a/compiler/xtensa/cpuinfo.pas b/compiler/xtensa/cpuinfo.pas index 61b042c5ff..a33337580b 100644 --- a/compiler/xtensa/cpuinfo.pas +++ b/compiler/xtensa/cpuinfo.pas @@ -137,6 +137,7 @@ Const ( CPUXTENSA_REGWINDOW, CPUXTENSA_HAS_SEXT, + CPUXTENSA_HAS_NSAx, CPUXTENSA_HAS_BOOLEAN_OPTION, CPUXTENSA_HAS_MUL32HIGH, CPUXTENSA_HAS_DIV, @@ -154,7 +155,7 @@ Const ( { cpu_none } [], { cpu_lx106 } [], - { cpu_lx6 } [CPUXTENSA_REGWINDOW, CPUXTENSA_HAS_SEXT, CPUXTENSA_HAS_BOOLEAN_OPTION, CPUXTENSA_HAS_MUL32HIGH, CPUXTENSA_HAS_DIV, CPUXTENSA_HAS_LOOPS] + { cpu_lx6 } [CPUXTENSA_REGWINDOW, CPUXTENSA_HAS_SEXT, CPUXTENSA_HAS_NSAx, CPUXTENSA_HAS_BOOLEAN_OPTION, CPUXTENSA_HAS_MUL32HIGH, CPUXTENSA_HAS_DIV, CPUXTENSA_HAS_LOOPS] ); fpu_capabilities : array[tfputype] of set of tfpuflags = diff --git a/rtl/inc/systemh.inc b/rtl/inc/systemh.inc index 8684da7e4d..0ae5f9b6c4 100644 --- a/rtl/inc/systemh.inc +++ b/rtl/inc/systemh.inc @@ -1143,7 +1143,7 @@ function fpc_SarInt64(Const AValue : Int64;const Shift : Byte): Int64;compilerpr {$endif} {$ifdef FPC_HAS_INTERNAL_BSR} -{$if defined(cpui386) or defined(cpux86_64) or defined(cpuarm) or defined(cpuaarch64) or defined(cpupowerpc32) or defined(cpupowerpc64)} +{$if defined(cpui386) or defined(cpux86_64) or defined(cpuarm) or defined(cpuaarch64) or defined(cpupowerpc32) or defined(cpupowerpc64) or defined(cpuxtensa)} {$define FPC_HAS_INTERNAL_BSR_BYTE} {$define FPC_HAS_INTERNAL_BSR_WORD} {$define FPC_HAS_INTERNAL_BSR_DWORD} From 4d4cdfb8047c8d770bf52a615bc49cac400223ba Mon Sep 17 00:00:00 2001 From: Mattias Gaertner Date: Sat, 26 Sep 2020 22:03:13 +0000 Subject: [PATCH 08/13] pastojs: ShortRefGlobals: same module class, record and enumtype git-svn-id: trunk@46964 - --- packages/fcl-passrc/src/pasresolver.pp | 26 +++ packages/pastojs/src/fppas2js.pp | 149 +++++++++++---- packages/pastojs/tests/tcoptimizations.pas | 206 +++++++++++++++------ 3 files changed, 289 insertions(+), 92 deletions(-) diff --git a/packages/fcl-passrc/src/pasresolver.pp b/packages/fcl-passrc/src/pasresolver.pp index d029bc416e..a140573ccf 100644 --- a/packages/fcl-passrc/src/pasresolver.pp +++ b/packages/fcl-passrc/src/pasresolver.pp @@ -2308,6 +2308,7 @@ type function GetPasPropertyStoredExpr(El: TPasProperty): TPasExpr; function GetPasPropertyDefaultExpr(El: TPasProperty): TPasExpr; function GetPasClassAncestor(ClassEl: TPasClassType; SkipAlias: boolean): TPasType; + function GetPasClassForward(ClassEl: TPasClassType): TPasClassType; function GetParentProcBody(El: TPasElement): TProcedureBody; function ProcHasImplElements(Proc: TPasProcedure): boolean; virtual; function IndexOfImplementedInterface(ClassEl: TPasClassType; aType: TPasType): integer; @@ -28009,6 +28010,31 @@ begin end; end; +function TPasResolver.GetPasClassForward(ClassEl: TPasClassType): TPasClassType; +var + Parent: TPasElement; + i: Integer; + CurClass: TPasClassType; + Ref: TResolvedReference; + Decls: TFPList; +begin + Result:=nil; + if ClassEl=nil then exit; + Parent:=ClassEl.Parent; + if not (Parent is TPasDeclarations) then + RaiseNotYetImplemented(20200926214106,ClassEl); + Decls:=TPasDeclarations(Parent).Classes; + for i:=0 to Decls.Count-1 do + begin + CurClass:=TPasClassType(Decls[i]); + if CurClass=ClassEl then exit; + if not CurClass.IsForward then continue; + Ref:=TResolvedReference(CurClass.CustomData); + if Ref.Declaration=ClassEl then + exit(TPasClassType(Ref.Declaration)); + end; +end; + function TPasResolver.GetParentProcBody(El: TPasElement): TProcedureBody; begin while El<>nil do diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp index fc5fdc25ca..9a6a9067ab 100644 --- a/packages/pastojs/src/fppas2js.pp +++ b/packages/pastojs/src/fppas2js.pp @@ -1673,6 +1673,7 @@ type function GetContextOfPasElement(El: TPasElement): TConvertContext; function GetFuncContextOfPasElement(El: TPasElement): TFunctionContext; function GetContextOfType(aType: TConvertContextClass): TConvertContext; + function GetMainSectionContext: TFunctionContext; function CurrentModeSwitches: TModeSwitches; function GetGlobalFunc: TFunctionContext; procedure WriteStack; @@ -1922,7 +1923,9 @@ type Function GetTypeInfoName(El: TPasType; AContext: TConvertContext; ErrorEl: TPasElement; Full: boolean = false): String; virtual; Function TransformArgName(Arg: TPasArgument; AContext: TConvertContext): string; virtual; - Function CreateGlobalAlias(El: TPasElement; JSPath: string; AContext: TConvertContext): string; virtual; + Function CreateGlobalAliasForeign(El: TPasElement; JSPath: string; AContext: TConvertContext): string; virtual; // El in other module + Function CreateGlobalAliasNull(El: TPasElement; Prefix: TPas2JSBuiltInName; + SectionContext: TSectionContext): TFCLocalIdentifier; virtual; // utility functions for creating stuff Function IsElementUsed(El: TPasElement): boolean; virtual; Function IsSystemUnit(aModule: TPasModule): boolean; virtual; @@ -7541,6 +7544,18 @@ begin until ctx=nil; end; +function TConvertContext.GetMainSectionContext: TFunctionContext; +var + Ctx: TConvertContext; +begin + Ctx:=Self; + repeat + if Ctx is TSectionContext then + Result:=TSectionContext(Ctx); + Ctx:=Ctx.Parent; + until Ctx=nil; +end; + function TConvertContext.CurrentModeSwitches: TModeSwitches; begin if Resolver=nil then @@ -14650,6 +14665,29 @@ Var end; end; + procedure InitForwards(Decls: TFPList; SectionContext: TSectionContext); + var + i: Integer; + P: TPasElement; + C: TClass; + begin + For i:=0 to Decls.Count-1 do + begin + P:=TPasElement(Decls[i]); + if not IsElementUsed(P) then continue; + C:=P.ClassType; + if (C=TPasClassType) and TPasClassType(P).IsForward then + continue; + if (C=TPasClassType) or (C=TPasRecordType) or (C=TPasEnumType) then + begin + // add var $lt = null; + CreateGlobalAliasNull(P,pbivnLocalTypeRef,SectionContext); + if (C=TPasClassType) or (C=TPasRecordType) then + InitForwards(TPasMembersType(P).Members,SectionContext); + end; + end; + end; + procedure InitSection(Section: TPasSection); var SectionScope: TPas2JSSectionScope; @@ -14665,6 +14703,18 @@ Var SectionCtx:=TSectionContext(AContext); Src:=SectionCtx.JSElement as TJSSourceElements; SectionCtx.HeaderIndex:=Src.Statements.Count; + + // add local vars for forward declarations + if (coShortRefGlobals in Options) + and (Section.ClassType<>TImplementationSection) then + begin + InitForwards(Section.Declarations,TSectionContext(AContext)); + if Section is TInterfaceSection then + begin + InitForwards(TPasModule(Section.Parent).ImplementationSection.Declarations, + TSectionContext(AContext)); + end; + end; end; var @@ -14846,7 +14896,7 @@ var P: TPasElement; Scope: TPas2JSClassScope; Ancestor: TPasType; - AncestorPath, OwnerName, DestructorName, FnName, IntfKind: String; + AncestorPath, OwnerName, DestructorName, FnName, IntfKind, JSName: String; C: TClass; AssignSt: TJSSimpleAssignStatement; NeedInitFunction, HasConstructor, IsJSFunction, NeedClassExt, @@ -14926,7 +14976,8 @@ begin Call.AddArg(CreatePrimitiveDotExpr(OwnerName,El)); // add parameter: string constant '"classname"' - ArgEx := CreateLiteralString(El,TransformElToJSName(El,AContext)); + JSName:=TransformElToJSName(El,AContext); + ArgEx:=CreateLiteralString(El,JSName); Call.AddArg(ArgEx); if El.ObjKind=okInterface then @@ -14985,6 +15036,18 @@ begin FuncContext.ThisVar.Element:=El; FuncContext.ThisVar.Kind:=cvkGlobal; + if coShortRefGlobals in Options then + begin + // $lt = this; + JSName:=AContext.GetLocalName(El,[cvkGlobal]); + if JSName='' then + RaiseNotSupported(El,AContext,20200926232402); + AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El)); + AssignSt.LHS:=CreatePrimitiveDotExpr(JSName,El); + AssignSt.Expr:=CreatePrimitiveDotExpr('this',El); + AddToSourceElements(Src,AssignSt); + end; + if IntfKind<>'' then begin // add this.$kind="com"; @@ -15279,7 +15342,7 @@ function TPasToJSConverter.ConvertEnumType(El: TPasEnumType; // maxvalue: 1 // }); // coShortRefGlobals: -// var $lt = this.TMyEnum ... +// $lt = this.TMyEnum ... var ObjectContect: TObjectContext; i: Integer; @@ -15295,7 +15358,7 @@ var Src: TJSSourceElements; ProcScope: TPas2JSProcedureScope; VarSt: TJSVariableStatement; - GlobalCtx: TConvertContext; + SectionContext: TSectionContext; begin Result:=nil; for i:=0 to El.Values.Count-1 do @@ -15344,32 +15407,17 @@ begin AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext); AssignSt.Expr:=Obj; Result:=AssignSt; - if (coShortRefGlobals in Options) and (AContext is TFunctionContext) then + if coShortRefGlobals in Options then begin - GlobalCtx:=AContext; - while (GlobalCtx.PasElement is TPasMembersType) do - GlobalCtx:=GlobalCtx.Parent; - if (GlobalCtx<>AContext) and (GlobalCtx is TFunctionContext) then - begin - // add to GlobalCtx: var $lt = {} - // add to local context: this.TypeName = $lt - if not (GlobalCtx.JSElement is TJSSourceElements) then - RaiseNotSupported(El,AContext,20200926181516,GetObjName(GlobalCtx.JSElement)); - Src:=TJSSourceElements(GlobalCtx.JSElement); - JSName:=TFunctionContext(AContext).CreateLocalIdentifier(GetBIName(pbivnLocalTypeRef)); - AssignSt.Expr:=CreatePrimitiveDotExpr(JSName,El); - - VarSt:=CreateVarStatement(JSName,Obj,El); - AddToSourceElements(Src,VarSt); - TFunctionContext(GlobalCtx).AddLocalVar(JSName,El,cvkGlobal,false); - end - else - begin - // var $lt = this.TypeName = {} - JSName:=TFunctionContext(AContext).CreateLocalIdentifier(GetBIName(pbivnLocalTypeRef)); - TFunctionContext(AContext).AddLocalVar(JSName,El,cvkGlobal,false); - Result:=CreateVarStatement(JSName,AssignSt,El); - end; + SectionContext:=TSectionContext(AContext.GetMainSectionContext); + JSName:=SectionContext.GetLocalName(El,[cvkGlobal]); + if JSName='' then + RaiseNotSupported(El,AContext,20200926232620); + // $lt = this.TypeName = {} + AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El)); + AssignSt.LHS:=CreatePrimitiveDotExpr(JSName,El); + AssignSt.Expr:=Result; + Result:=AssignSt; end; end; @@ -16963,11 +17011,9 @@ var SectionCtx: TSectionContext; begin if JS=nil then exit; - SectionCtx:=TSectionContext(aContext.GetContextOfType(TSectionContext)); + SectionCtx:=TSectionContext(aContext.GetMainSectionContext); if SectionCtx=nil then RaiseNotSupported(PosEl,aContext,20200606142555); - if SectionCtx.Parent is TSectionContext then - SectionCtx:=TSectionContext(SectionCtx.Parent); SectionCtx.AddHeaderStatement(JS); end; @@ -24220,7 +24266,7 @@ begin RaiseNotSupported(El,AContext,20200609230526,GetObjPath(El)); Result:=Result+'.'+TransformElToJSName(El,AContext); if ShortRefGlobals then - Result:=CreateGlobalAlias(El,Result,AContext); + Result:=CreateGlobalAliasForeign(El,Result,AContext); end; procedure TPasToJSConverter.CreateProcedureCall(var Call: TJSCallExpression; @@ -25332,7 +25378,7 @@ var DelaySrc: TJSSourceElements; DelayFuncContext: TFunctionContext; Call: TJSCallExpression; - JSParentName: String; + JSParentName, JSName: String; FunDecl: TJSFunctionDeclarationStatement; Src: TJSSourceElements; FuncContext: TFunctionContext; @@ -25345,6 +25391,7 @@ var NewFields, Vars, Methods: TFPList; ok, IsComplex, SpecializeDelay: Boolean; VarSt: TJSVariableStatement; + AssignSt: TJSSimpleAssignStatement; begin Result:=nil; if El.Name='' then @@ -25413,6 +25460,18 @@ begin FuncContext.ThisVar.Element:=El; FuncContext.ThisVar.Kind:=cvkGlobal; + if coShortRefGlobals in Options then + begin + // $lt = this; + JSName:=AContext.GetLocalName(El,[cvkGlobal]); + if JSName='' then + RaiseNotSupported(El,AContext,20200926235501); + AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El)); + AssignSt.LHS:=CreatePrimitiveDotExpr(JSName,El); + AssignSt.Expr:=CreatePrimitiveDotExpr('this',El); + AddToSourceElements(Src,AssignSt); + end; + // init fields NewFields:=TFPList.Create; Vars:=TFPList.Create; @@ -25725,7 +25784,7 @@ begin Result:=GetBIName(pbivnModules)+'.'+Result; if coShortRefGlobals in Options then - Result:=CreateGlobalAlias(El,Result,AContext); + Result:=CreateGlobalAliasForeign(El,Result,AContext); end; end; @@ -25972,7 +26031,7 @@ begin Result:=TransformToJSName(Arg,Result,true,AContext); end; -function TPasToJSConverter.CreateGlobalAlias(El: TPasElement; JSPath: string; +function TPasToJSConverter.CreateGlobalAliasForeign(El: TPasElement; JSPath: string; AContext: TConvertContext): string; var ElModule, MyModule: TPasModule; @@ -25998,9 +26057,7 @@ begin else begin // El is from another unit - SectionContext:=TSectionContext(AContext.GetContextOfType(TSectionContext)); - if SectionContext.Parent is TSectionContext then - SectionContext:=TSectionContext(SectionContext.Parent); + SectionContext:=TSectionContext(AContext.GetMainSectionContext); FuncContext:=AContext.GetFunctionContext; if El is TPasModule then @@ -26036,6 +26093,18 @@ begin end; end; +function TPasToJSConverter.CreateGlobalAliasNull(El: TPasElement; + Prefix: TPas2JSBuiltInName; SectionContext: TSectionContext + ): TFCLocalIdentifier; +var + V: TJSVariableStatement; +begin + // insert var $lt = null; + Result:=SectionContext.AddLocalVar(GetBIName(Prefix),El,cvkGlobal,true); + V:=CreateVarStatement(Result.Name,CreateLiteralNull(El),El); + AddHeaderStatement(V,El,SectionContext); +end; + function TPasToJSConverter.ConvertPasElement(El: TPasElement; Resolver: TPas2JSResolver): TJSElement; var diff --git a/packages/pastojs/tests/tcoptimizations.pas b/packages/pastojs/tests/tcoptimizations.pas index d23c23680c..eb5cda8579 100644 --- a/packages/pastojs/tests/tcoptimizations.pas +++ b/packages/pastojs/tests/tcoptimizations.pas @@ -62,6 +62,7 @@ type procedure TestOptShortRefGlobals_Property; procedure TestOptShortRefGlobals_GenericFunction; procedure TestOptShortRefGlobals_SameUnit_EnumType; + procedure TestOptShortRefGlobals_SameUnit_ClassType; // Whole Program Optimization procedure TestWPO_OmitLocalVar; @@ -246,24 +247,26 @@ begin ConvertProgram; CheckSource('TestOptShortRefGlobals_Program', LinesToStr([ + 'var $lt = null;', 'var $lm = pas.UnitA;', - 'var $lt = $lm.TBird;', - 'var $lt1 = $lm.TRec;', - 'rtl.createClass(this, "TEagle", $lt, function () {', + 'var $lt1 = $lm.TBird;', + 'var $lt2 = $lm.TRec;', + 'rtl.createClass(this, "TEagle", $lt1, function () {', + ' $lt = this;', ' this.Run = function (w) {', ' var Result = 0;', ' return Result;', ' };', '});', 'this.e = null;', - 'this.r = $lt1.$new();', + 'this.r = $lt2.$new();', 'this.c = {};', '']), LinesToStr([ - '$mod.e = $mod.TEagle.$create("Create");', - '$lm.b = $lt.$create("Create");', - '$lt.c = $mod.e.c + 1;', - '$mod.r.x = $lt.c;', + '$mod.e = $lt.$create("Create");', + '$lm.b = $lt1.$create("Create");', + '$lt1.c = $mod.e.c + 1;', + '$mod.r.x = $lt1.c;', '$mod.r.x = $lm.b.c;', '$mod.r.x = $mod.e.$class.Run(5);', '$mod.r.x = $mod.e.$class.Run(5);', @@ -352,42 +355,46 @@ begin CheckSource('TestOptShortRefGlobals_Unit_FromIntfImpl_ToIntfImpl', LinesToStr([ 'var $impl = $mod.$impl;', - 'var $lm = pas.UnitA;', - 'var $lt = $lm.TBird;', - 'var $lm1 = null;', + 'var $lt = null;', 'var $lt1 = null;', - 'var $lt2 = null;', + 'var $lm = pas.UnitA;', + 'var $lt2 = $lm.TBird;', + 'var $lm1 = null;', 'var $lt3 = null;', - 'rtl.createClass(this, "TEagle", $lt, function () {', + 'var $lt4 = null;', + 'var $lt5 = null;', + 'rtl.createClass(this, "TEagle", $lt2, function () {', + ' $lt = this;', ' this.Fly = function () {', - ' $impl.TRedAnt.$create("Create");', ' $lt1.$create("Create");', + ' $lt3.$create("Create");', + ' $lt2.$create("Create");', ' $lt.$create("Create");', - ' $mod.TEagle.$create("Create");', ' };', '});', '']), LinesToStr([ - '$impl.RedAnt = $impl.TRedAnt.$create("Create");', - '$impl.Ant = $lt1.$create("Create");', - '$impl.Bird = $lt.$create("Create");', - '$impl.Eagle = $mod.TEagle.$create("Create");', - '$lt3.$create("Create");', + '$impl.RedAnt = $lt1.$create("Create");', + '$impl.Ant = $lt3.$create("Create");', + '$impl.Bird = $lt2.$create("Create");', + '$impl.Eagle = $lt.$create("Create");', + '$lt5.$create("Create");', '$impl.Eagle.Fly();', '$impl.RedAnt.Run();', '']), LinesToStr([ '$lm1 = pas.UnitB;', - '$lt1 = $lm1.TAnt;', - '$lt2 = $lm1.TBear;', - '$lt3 = $lm1.TFrog;', - 'rtl.createClass($impl, "TRedAnt", $lt1, function () {', + '$lt3 = $lm1.TAnt;', + '$lt4 = $lm1.TBear;', + '$lt5 = $lm1.TFrog;', + 'rtl.createClass($impl, "TRedAnt", $lt3, function () {', + ' $lt1 = this;', ' this.Run = function () {', - ' $impl.TRedAnt.$create("Create");', ' $lt1.$create("Create");', - ' $lt.$create("Create");', - ' $mod.TEagle.$create("Create");', + ' $lt3.$create("Create");', ' $lt2.$create("Create");', + ' $lt.$create("Create");', + ' $lt4.$create("Create");', ' };', '});', '$impl.RedAnt = null;', @@ -431,9 +438,11 @@ begin ConvertUnit; CheckSource('TestOptShortRefGlobals_Property', LinesToStr([ + 'var $lt = null;', 'var $lm = pas.UnitA;', - 'var $lt = $lm.TBird;', - 'rtl.createClass(this, "TEagle", $lt, function () {', + 'var $lt1 = $lm.TBird;', + 'rtl.createClass(this, "TEagle", $lt1, function () {', + ' $lt = this;', ' this.Fly = function (o) {', ' this.Fly(this.FWing);', ' this.Fly(this.FLeg);', @@ -475,11 +484,13 @@ begin ConvertUnit; CheckSource('TestOptShortRefGlobals_GenericFunction', LinesToStr([ + 'var $lt = null;', 'var $lm = pas.system;', - 'var $lt = $lm.TObject;', + 'var $lt1 = $lm.TObject;', 'var $lm1 = pas.UnitA;', 'var $lp = $lm1.Run$G1;', - 'rtl.createClass(this, "TEagle", $lt, function () {', + 'rtl.createClass(this, "TEagle", $lt1, function () {', + ' $lt = this;', '});', 'this.Fly = function () {', ' $lp(null);', @@ -498,23 +509,25 @@ begin '{$optimization JSShortRefGlobals}', 'interface', 'type', - ' TEnum = (red,blue);', ' TBird = class', ' type', ' TFlag = (big,small);', ' procedure Fly;', ' end;', - 'var f: TBird.TFlag;', + ' TEnum = (red,blue);', + 'var', + ' e: TEnum;', + ' f: TBird.TFlag;', 'procedure Run;', 'implementation', 'procedure TBird.Fly;', 'begin', + ' e:=blue;', ' f:=small;', 'end;', 'procedure Run;', 'type TSub = (left,right);', - 'var e: TEnum;', - ' s: TSub;', + 'var s: TSub;', 'begin', ' e:=red;', ' s:=right;', @@ -524,26 +537,31 @@ begin ConvertUnit; CheckSource('TestOptShortRefGlobals_SameUnit_EnumType', LinesToStr([ + 'var $lt = null;', + 'var $lt1 = null;', + 'var $lt2 = null;', 'var $lm = pas.system;', - 'var $lt1 = $lm.TObject;', - 'var $lt = this.TEnum = {', - ' "0": "red",', - ' red: 0,', - ' "1": "blue",', - ' blue: 1', - '};', - 'var $lt2 = {', + 'var $lt3 = $lm.TObject;', + 'rtl.createClass(this, "TBird", $lt3, function () {', + ' $lt = this;', + ' $lt1 = this.TFlag = {', ' "0": "big",', ' big: 0,', ' "1": "small",', ' small: 1', ' };', - 'rtl.createClass(this, "TBird", $lt1, function () {', - ' this.TFlag = $lt2;', ' this.Fly = function () {', - ' $mod.f = $lt2.small;', + ' $mod.e = $lt2.blue;', + ' $mod.f = $lt1.small;', ' };', '});', + '$lt2 = this.TEnum = {', + ' "0": "red",', + ' red: 0,', + ' "1": "blue",', + ' blue: 1', + '};', + 'this.e = 0;', 'this.f = 0;', 'var TSub = {', ' "0": "left",', @@ -552,11 +570,10 @@ begin ' right: 1', '};', 'this.Run = function () {', - ' var e = 0;', ' var s = 0;', - ' e = $lt.red;', + ' $mod.e = $lt2.red;', ' s = TSub.right;', - ' $mod.f = $lt2.big;', + ' $mod.f = $lt1.big;', '};', '']), LinesToStr([ @@ -565,6 +582,91 @@ begin ''])); end; +procedure TTestOptimizations.TestOptShortRefGlobals_SameUnit_ClassType; +begin + WithTypeInfo:=true; + StartUnit(true,[supTObject]); + Add([ + '{$optimization JSShortRefGlobals}', + 'interface', + 'type', + ' TBird = class;', + ' TAnt = class', + ' type', + ' TLeg = class', + ' end;', + ' procedure Run;', + ' published', + ' Bird: TBird;', + ' end;', + ' TBird = class', + ' procedure Fly;', + ' end;', + 'implementation', + 'type', + ' TFrog = class', + ' end;', + 'procedure TAnt.Run;', + 'begin', + ' if typeinfo(TBird)=nil then;', + ' Bird:=TBird.Create;', + ' TLeg.Create;', + ' TFrog.Create;', + 'end;', + 'procedure TBird.Fly;', + 'begin', + ' if typeinfo(TAnt)=nil then;', + 'end;', + '']); + ConvertUnit; + CheckSource('TestOptShortRefGlobals_SameUnit_EnumType', + LinesToStr([ + 'var $impl = $mod.$impl;', + 'var $lt = null;', + 'var $lt1 = null;', + 'var $lt2 = null;', + 'var $lt3 = null;', + 'var $lm = pas.system;', + 'var $lt4 = $lm.TObject;', + 'this.$rtti.$Class("TBird");', + 'rtl.createClass(this, "TAnt", $lt4, function () {', + ' $lt = this;', + ' rtl.createClass(this, "TLeg", $lt4, function () {', + ' $lt1 = this;', + ' });', + ' this.$init = function () {', + ' $lt4.$init.call(this);', + ' this.Bird = null;', + ' };', + ' this.$final = function () {', + ' this.Bird = undefined;', + ' $lt4.$final.call(this);', + ' };', + ' this.Run = function () {', + ' if ($mod.$rtti["TBird"] === null) ;', + ' this.Bird = $lt2.$create("Create");', + ' $lt1.$create("Create");', + ' $lt3.$create("Create");', + ' };', + ' var $r = this.$rtti;', + ' $r.addField("Bird", $mod.$rtti["TBird"]);', + '});', + 'rtl.createClass(this, "TBird", $lt4, function () {', + ' $lt2 = this;', + ' this.Fly = function () {', + ' if ($mod.$rtti["TAnt"] === null) ;', + ' };', + '});', + '']), + LinesToStr([ + '']), + LinesToStr([ + 'rtl.createClass($impl, "TFrog", $lt4, function () {', + ' $lt3 = this;', + '});', + ''])); +end; + procedure TTestOptimizations.TestWPO_OmitLocalVar; begin StartProgram(false); @@ -1386,7 +1488,7 @@ procedure TTestOptimizations.TestWPO_ConstructorDefaultValueConst; var ActualSrc, ExpectedSrc: String; begin - Converter.Options:=Converter.Options-[coNoTypeInfo]; + WithTypeInfo:=true; StartProgram(true); Add([ 'const gcBlack = 0;', @@ -1437,7 +1539,7 @@ procedure TTestOptimizations.TestWPO_RTTI_PublishedField; var ActualSrc, ExpectedSrc: String; begin - Converter.Options:=Converter.Options-[coNoTypeInfo]; + WithTypeInfo:=true; StartProgram(true); Add('type'); Add(' TArrA = array of char;'); @@ -1485,7 +1587,7 @@ procedure TTestOptimizations.TestWPO_RTTI_TypeInfo; var ActualSrc, ExpectedSrc: String; begin - Converter.Options:=Converter.Options-[coNoTypeInfo]; + WithTypeInfo:=true; StartProgram(true); Add('type'); Add(' TArrA = array of char;'); From 8246aae1aed25c3e856694d1bf9b27e4f9dc714c Mon Sep 17 00:00:00 2001 From: Mattias Gaertner Date: Sat, 26 Sep 2020 22:27:57 +0000 Subject: [PATCH 09/13] fcl-passrc: fixed compile with pas2js git-svn-id: trunk@46965 - --- packages/fcl-passrc/src/pscanner.pp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/fcl-passrc/src/pscanner.pp b/packages/fcl-passrc/src/pscanner.pp index 0bda2df115..999baa829a 100644 --- a/packages/fcl-passrc/src/pscanner.pp +++ b/packages/fcl-passrc/src/pscanner.pp @@ -4200,7 +4200,7 @@ var s: string; l: integer; {$endif} - LE : String[2]; + LE : String{$ifdef fpc}[2]{$endif}; procedure FetchCurTokenString; inline; begin @@ -4327,7 +4327,7 @@ begin '(': begin Inc(FTokenPos); - if {$ifdef UsePChar}FTokenPos[0] = '.'{$else}(FTokenPos>l) or (s[FTokenPos]<>'.'){$endif} then + if {$ifdef UsePChar}FTokenPos[0] = '.'{$else}(FTokenPos<=l) and (s[FTokenPos]='.'){$endif} then begin Inc(FTokenPos); Result := tkSquaredBraceOpen; @@ -4519,7 +4519,7 @@ begin Inc(FTokenPos); until {$ifdef UsePChar}not (FTokenPos[0] in Digits){$else}(FTokenPos>l) or not (s[FTokenPos] in Digits){$endif}; if {$ifdef UsePChar}(FTokenPos[0]='.') and (FTokenPos[1]<>'.') and (FTokenPos[1]<>')'){$else} - (FTokenPos<=l) and (s[FTokenPos]='.') and ((FTokenPos=l) or (s[FTokenPos+1]<>'.') and ((FTokenPos=l) or (s[FTokenPos+1]<>')')){$endif}then + (FTokenPos<=l) and (s[FTokenPos]='.') and ((FTokenPos=l) or ((s[FTokenPos+1]<>'.') and (s[FTokenPos+1]<>')'))){$endif}then begin inc(FTokenPos); while {$ifdef UsePChar}FTokenPos[0] in Digits{$else}(FTokenPos<=l) and (s[FTokenPos] in Digits){$endif} do From c1e700b3fe10d2139af666528fcacad6041afa45 Mon Sep 17 00:00:00 2001 From: Mattias Gaertner Date: Sat, 26 Sep 2020 22:36:30 +0000 Subject: [PATCH 10/13] fcl-js: clean up git-svn-id: trunk@46966 - --- packages/fcl-js/src/jsbase.pp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/fcl-js/src/jsbase.pp b/packages/fcl-js/src/jsbase.pp index e863a364ca..c70cb427b8 100644 --- a/packages/fcl-js/src/jsbase.pp +++ b/packages/fcl-js/src/jsbase.pp @@ -19,11 +19,9 @@ unit jsbase; interface -uses - {$ifdef pas2js} - js, - {$endif} - Classes; +{$ifdef pas2js} +uses js; +{$endif} const MinSafeIntDouble = -$1fffffffffffff; // -9007199254740991 53 bits (52 explicitly stored) From d5d9635cd9fbdfdcf22c86c5a6b0a1d43cd6b9aa Mon Sep 17 00:00:00 2001 From: Mattias Gaertner Date: Sat, 26 Sep 2020 22:36:45 +0000 Subject: [PATCH 11/13] fcl-passrc: clean up git-svn-id: trunk@46967 - --- packages/fcl-passrc/src/pscanner.pp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/fcl-passrc/src/pscanner.pp b/packages/fcl-passrc/src/pscanner.pp index 999baa829a..069c83ded5 100644 --- a/packages/fcl-passrc/src/pscanner.pp +++ b/packages/fcl-passrc/src/pscanner.pp @@ -4196,11 +4196,11 @@ var {$ifdef UsePChar} OldLength: integer; Ch: Char; + LE: string[2]; {$else} s: string; l: integer; {$endif} - LE : String{$ifdef fpc}[2]{$endif}; procedure FetchCurTokenString; inline; begin @@ -4336,7 +4336,9 @@ begin Result := tkBraceOpen else begin + {$ifdef UsePChar} LE:=LineEnding; + {$endif} // Old-style multi-line comment Inc(FTokenPos); TokenStart := FTokenPos; @@ -4353,13 +4355,11 @@ begin SetLength(FCurTokenString, OldLength + SectionLength + length(LineEnding)); // Corrected JC if SectionLength > 0 then Move(TokenStart^, FCurTokenString[OldLength + 1],SectionLength); - - // Corrected JC: Append the correct lineending Inc(OldLength, SectionLength); for Ch in LE do begin - Inc(OldLength); - FCurTokenString[OldLength] := Ch; + Inc(OldLength); + FCurTokenString[OldLength] := Ch; end; {$else} FCurTokenString:=FCurTokenString+copy(FCurLine,TokenStart,SectionLength)+LineEnding; // Corrected JC @@ -4654,11 +4654,11 @@ begin end; '{': // Multi-line comment begin - LE:=LineEnding; Inc(FTokenPos); TokenStart := FTokenPos; FCurTokenString := ''; {$ifdef UsePChar} + LE:=LineEnding; OldLength := 0; {$endif} NestingLevel := 0; From 7945631ff1fcc7bb28de9c4eba81fe5c74058233 Mon Sep 17 00:00:00 2001 From: Mattias Gaertner Date: Sat, 26 Sep 2020 22:36:55 +0000 Subject: [PATCH 12/13] pastojs: clean up git-svn-id: trunk@46968 - --- packages/pastojs/src/fppas2js.pp | 1 - packages/pastojs/src/fppjssrcmap.pp | 2 +- packages/pastojs/src/pas2jscompiler.pp | 1 + packages/pastojs/src/pas2jscompilercfg.pp | 2 +- packages/pastojs/src/pas2jsfscompiler.pp | 2 +- packages/pastojs/src/pas2jsresstrfile.pp | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp index 9a6a9067ab..91007f2de6 100644 --- a/packages/pastojs/src/fppas2js.pp +++ b/packages/pastojs/src/fppas2js.pp @@ -466,7 +466,6 @@ interface uses {$ifdef pas2js} - js, {$else} AVL_Tree, {$endif} diff --git a/packages/pastojs/src/fppjssrcmap.pp b/packages/pastojs/src/fppjssrcmap.pp index 621060c392..681a9feb52 100644 --- a/packages/pastojs/src/fppjssrcmap.pp +++ b/packages/pastojs/src/fppjssrcmap.pp @@ -25,7 +25,7 @@ unit FPPJsSrcMap; interface uses - Classes, SysUtils, math, + SysUtils, math, jswriter, jstree, JSSrcMap; type diff --git a/packages/pastojs/src/pas2jscompiler.pp b/packages/pastojs/src/pas2jscompiler.pp index 01f31b00a3..eb5f080778 100644 --- a/packages/pastojs/src/pas2jscompiler.pp +++ b/packages/pastojs/src/pas2jscompiler.pp @@ -1182,6 +1182,7 @@ begin // maybe emit message ? FResourceHandler.StartUnit(PasModule.Name); FResourceHandler.HandleResource(aFileName,aOptions); + if Sender=nil then ; end; function TPas2jsCompilerFile.OnConverterIsElementUsed(Sender: TObject; diff --git a/packages/pastojs/src/pas2jscompilercfg.pp b/packages/pastojs/src/pas2jscompilercfg.pp index 480f0bb081..5b5d896f68 100644 --- a/packages/pastojs/src/pas2jscompilercfg.pp +++ b/packages/pastojs/src/pas2jscompilercfg.pp @@ -26,7 +26,7 @@ uses {$IFDEF NodeJS} node.fs, {$ENDIF} - Classes, SysUtils, Pas2jsFileUtils, Pas2JSFS, Pas2jsCompiler; + SysUtils, Pas2jsFileUtils, Pas2JSFS, Pas2jsCompiler; Type TPas2JSFileConfigSupport = Class(TPas2JSConfigSupport) diff --git a/packages/pastojs/src/pas2jsfscompiler.pp b/packages/pastojs/src/pas2jsfscompiler.pp index aeaeda08c9..53a7027ed5 100644 --- a/packages/pastojs/src/pas2jsfscompiler.pp +++ b/packages/pastojs/src/pas2jsfscompiler.pp @@ -23,7 +23,7 @@ unit Pas2JSFSCompiler; interface uses - Classes, SysUtils, + SysUtils, PasUseAnalyzer, Pas2jsFileCache, Pas2jsCompiler, Pas2JSFS, diff --git a/packages/pastojs/src/pas2jsresstrfile.pp b/packages/pastojs/src/pas2jsresstrfile.pp index 53564a2ace..883a4d7ca4 100644 --- a/packages/pastojs/src/pas2jsresstrfile.pp +++ b/packages/pastojs/src/pas2jsresstrfile.pp @@ -5,7 +5,7 @@ unit pas2jsresstrfile; interface uses - Classes, SysUtils, fpJSON; + SysUtils, fpJSON; Type From 35f59b6736bf1d36cbf71e43b0f13009cebf5ff5 Mon Sep 17 00:00:00 2001 From: Mattias Gaertner Date: Sat, 26 Sep 2020 22:56:41 +0000 Subject: [PATCH 13/13] pastojs: shortrefglobals: local recordtype git-svn-id: trunk@46969 - --- packages/fcl-passrc/src/pparser.pp | 10 +- packages/pastojs/src/fppas2js.pp | 5 +- packages/pastojs/tests/tcoptimizations.pas | 112 ++++++++++++++++++++- 3 files changed, 119 insertions(+), 8 deletions(-) diff --git a/packages/fcl-passrc/src/pparser.pp b/packages/fcl-passrc/src/pparser.pp index 922ecfcf31..1c4d93e49f 100644 --- a/packages/fcl-passrc/src/pparser.pp +++ b/packages/fcl-passrc/src/pparser.pp @@ -123,11 +123,11 @@ resourcestring SParserNoConstructorAllowed = 'Constructors or Destructors are not allowed in Interfaces or Records'; SParserNoFieldsAllowedInX = 'Fields are not allowed in %s'; SParserInvalidRecordVisibility = 'Records can only have public and (strict) private as visibility specifiers'; - SErrRecordConstantsNotAllowed = 'Record constants not allowed at this location.'; - SErrRecordVariablesNotAllowed = 'Record variables not allowed at this location.'; - SErrRecordMethodsNotAllowed = 'Record methods not allowed at this location.'; - SErrRecordPropertiesNotAllowed = 'Record properties not allowed at this location.'; - SErrRecordTypesNotAllowed = 'Record types not allowed at this location.'; + SErrRecordConstantsNotAllowed = 'Record constants not allowed at this location'; + SErrRecordVariablesNotAllowed = 'Record variables not allowed at this location'; + SErrRecordMethodsNotAllowed = 'Record methods not allowed at this location'; + SErrRecordPropertiesNotAllowed = 'Record properties not allowed at this location'; + SErrRecordTypesNotAllowed = 'Record types not allowed at this location'; SParserTypeNotAllowedHere = 'Type "%s" not allowed here'; SParserNotAnOperand = 'Not an operand: (%d : %s)'; SParserArrayPropertiesCannotHaveDefaultValue = 'Array properties cannot have default value'; diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp index 91007f2de6..dfdfbafd21 100644 --- a/packages/pastojs/src/fppas2js.pp +++ b/packages/pastojs/src/fppas2js.pp @@ -25422,7 +25422,8 @@ begin RaiseNotSupported(El,AContext,20190105104054); // local record type elevated to global scope Src:=TJSSourceElements(AContext.JSElement); - VarSt:=CreateVarStatement(TransformElToJSName(El,AContext),Call,El); + JSName:=TransformElToJSName(El,AContext); + VarSt:=CreateVarStatement(JSName,Call,El); AddToSourceElements(Src,VarSt); // keep Result=nil // add parameter: parent = null Call.AddArg(CreateLiteralNull(El)); @@ -25459,7 +25460,7 @@ begin FuncContext.ThisVar.Element:=El; FuncContext.ThisVar.Kind:=cvkGlobal; - if coShortRefGlobals in Options then + if (coShortRefGlobals in Options) and not (El.Parent is TProcedureBody) then begin // $lt = this; JSName:=AContext.GetLocalName(El,[cvkGlobal]); diff --git a/packages/pastojs/tests/tcoptimizations.pas b/packages/pastojs/tests/tcoptimizations.pas index eb5cda8579..84b40b0411 100644 --- a/packages/pastojs/tests/tcoptimizations.pas +++ b/packages/pastojs/tests/tcoptimizations.pas @@ -63,6 +63,7 @@ type procedure TestOptShortRefGlobals_GenericFunction; procedure TestOptShortRefGlobals_SameUnit_EnumType; procedure TestOptShortRefGlobals_SameUnit_ClassType; + procedure TestOptShortRefGlobals_SameUnit_RecordType; // Whole Program Optimization procedure TestWPO_OmitLocalVar; @@ -619,7 +620,7 @@ begin 'end;', '']); ConvertUnit; - CheckSource('TestOptShortRefGlobals_SameUnit_EnumType', + CheckSource('TestOptShortRefGlobals_SameUnit_ClassType', LinesToStr([ 'var $impl = $mod.$impl;', 'var $lt = null;', @@ -667,6 +668,115 @@ begin ''])); end; +procedure TTestOptimizations.TestOptShortRefGlobals_SameUnit_RecordType; +begin + StartUnit(true,[supTObject]); + Add([ + '{$optimization JSShortRefGlobals}', + '{$modeswitch advancedrecords}', + 'interface', + 'type', + ' TAnt = record', + ' type', + ' TLeg = record', + ' l: word;', + ' end;', + ' procedure Run;', + ' Leg: TLeg;', + ' end;', + 'implementation', + 'type', + ' TBird = record', + ' b: word;', + ' end;', + 'procedure TAnt.Run;', + 'type', + ' TFoot = record', + ' f: word;', + ' end;', + 'var', + ' b: TBird;', + ' l: TLeg;', + ' a: TAnt;', + ' f: TFoot;', + 'begin', + ' b.b:=1;', + ' l.l:=2;', + ' a.Leg.l:=3;', + ' f.f:=4;', + 'end;', + '']); + ConvertUnit; + CheckSource('TestOptShortRefGlobals_SameUnit_RecordType', + LinesToStr([ + 'var $impl = $mod.$impl;', + 'var $lt = null;', + 'var $lt1 = null;', + 'var $lt2 = null;', + 'rtl.recNewT(this, "TAnt", function () {', + ' $lt = this;', + ' rtl.recNewT($lt, "TLeg", function () {', + ' $lt1 = this;', + ' this.l = 0;', + ' this.$eq = function (b) {', + ' return this.l === b.l;', + ' };', + ' this.$assign = function (s) {', + ' this.l = s.l;', + ' return this;', + ' };', + ' });', + ' this.$new = function () {', + ' var r = Object.create(this);', + ' r.Leg = $lt1.$new();', + ' return r;', + ' };', + ' this.$eq = function (b) {', + ' return this.Leg.$eq(b.Leg);', + ' };', + ' this.$assign = function (s) {', + ' this.Leg.$assign(s.Leg);', + ' return this;', + ' };', + ' var TFoot = rtl.recNewT(null, "", function () {', + ' this.f = 0;', + ' this.$eq = function (b) {', + ' return this.f === b.f;', + ' };', + ' this.$assign = function (s) {', + ' this.f = s.f;', + ' return this;', + ' };', + ' });', + ' this.Run = function () {', + ' var b = $lt2.$new();', + ' var l = $lt1.$new();', + ' var a = $lt.$new();', + ' var f = TFoot.$new();', + ' b.b = 1;', + ' l.l = 2;', + ' a.Leg.l = 3;', + ' f.f = 4;', + ' };', + '}, true);', + '']), + LinesToStr([ + '']), + LinesToStr([ + 'rtl.recNewT($impl, "TBird", function () {', + ' $lt2 = this;', + ' this.b = 0;', + ' this.$eq = function (b) {', + ' return this.b === b.b;', + ' };', + ' this.$assign = function (s) {', + ' this.b = s.b;', + ' return this;', + ' };', + '});', + ''])); +end; + procedure TTestOptimizations.TestWPO_OmitLocalVar; begin StartProgram(false);