Skip to content

Optimize in FCS #3784

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 37 commits into from
Feb 17, 2018
Merged

Optimize in FCS #3784

merged 37 commits into from
Feb 17, 2018

Conversation

forki
Copy link
Contributor

@forki forki commented Oct 20, 2017

@forki
Copy link
Contributor Author

forki commented Oct 20, 2017

what's that outFile?

@forki forki changed the title Optimize in FCS [WIP] Optimize in FCS Oct 20, 2017
@forki
Copy link
Contributor Author

forki commented Oct 20, 2017

/cc @kjnilsson probably also interesting for fez

@kjnilsson
Copy link

Looks fantastic.

@dsyme
Copy link
Contributor

dsyme commented Oct 25, 2017

@forki Impressive. I took a very quick glance and it look totally feasible. I thought this would need much more work.

@forki
Copy link
Contributor Author

forki commented Oct 25, 2017

@dsyme what we need is to flag the optimizer for creating ilasm statements. These are hard to translate back in fable

@forki forki closed this Oct 25, 2017
@forki forki reopened this Oct 25, 2017
@forki forki closed this Oct 26, 2017
@forki forki reopened this Oct 26, 2017
@ncave
Copy link
Contributor

ncave commented Nov 26, 2017

@forki IMO we just need to add the missing ILAsm conversions in Exprs.fs.
I added a few here as a test, let me know if you want me to submit them to your PR.
Here is a test REPL so you can try them live: https://ncave.github.io/fable-repl-test

@forki
Copy link
Contributor Author

forki commented Nov 26, 2017 via email

@ncave
Copy link
Contributor

ncave commented Nov 26, 2017

@forki See PR#37.

@alfonsogarciacaro
Copy link
Contributor

So is this already working? Will it be merged? Or can we make a custom build for Fable? I used the Fable.FCS package in the past for that, we could reuse it now 😄

@ncave
Copy link
Contributor

ncave commented Nov 29, 2017

@alfonsogarciacaro All good questions idk the answer to. But you can definitely go ahead with a custom build if you want to try it. It's unfortunate that there are no FCS build artefacts for netstandard.

@ncave
Copy link
Contributor

ncave commented Nov 29, 2017

@alfonsogarciacaro Just FYI if you are custom building the FCS for netstandard, you may have to fix the embedded resource name in the .fsproj a little bit like that:

    <EmbeddedResource Include="$(FSharpSourcesRoot)/fsharp/FSStrings.resx">
      <Link>FSStrings.resx</Link>
      <LogicalName>fsstrings.resources</LogicalName>
    </EmbeddedResource>

@ncave
Copy link
Contributor

ncave commented Nov 29, 2017

@alfonsogarciacaro There are still a few more ILAsm that need to be properly translated before it can pass all Fable tests, (e.g. I_box, I_call).

@alfonsogarciacaro
Copy link
Contributor

@ncave Thanks a lot for the info! Hmm, I don't remember doing anything in particular last time I did a custom build, but it was FCS repo (which I'm much more familiarized with) not this one. Would it be possible to create a branch with these changes on your FCS fork?

@forki
Copy link
Contributor Author

forki commented Nov 29, 2017 via email

@alfonsogarciacaro
Copy link
Contributor

Sounds like a plan! Awesome, thank you @forki 👏 🎉

@ncave
Copy link
Contributor

ncave commented Nov 29, 2017

@alfonsogarciacaro

Would it be possible to create a branch with these changes on your FCS fork?

Not a problem, but let me add the missing ILAsm translations first.

Copy link
Contributor

@dsyme dsyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks a very promising FCS feature. I don't see any outright errors - but we need to add testing.

  1. Please find all the places where test assembly contents and also apply optimizations

  2. Please check if we have a test that gets the assembly contents for FSharp.Core - I did do that manually but I don't think it's automated - ideally we would add this test and also get the optimized TAST for FSHarp.Core - that is an excellent stress test


member info.AssemblyContents = FSharpAssemblyContents(info.TypedImplementionFiles)

member info.OptimizedAssemblyContents =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change to GetOptimizedAssemblyContents() since it involves potentially very long computation (e.g. we don't want it triggering in the debugger when looking at one of these objects)


member info.OptimizedAssemblyContents =
let tcGlobals, thisCcu, tcImports, mimpls = info.TypedImplementionFiles
let outfile = null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is outfile used for and can we pass in a correct (or at least non-null) value here?

Copy link
Contributor

@dsyme dsyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request adding tests etc. per comment above

@dsyme
Copy link
Contributor

dsyme commented Jan 31, 2018

This is really good - I believe the typeof inversion is the only one I'm concerned about now

@ncave
Copy link
Contributor

ncave commented Feb 2, 2018

@dsyme Thanks for the review, here are the changes since:

  • fixed checked ops
  • fixed checked conv
  • fixed typeof
  • fixed string hash
  • fixed dual conv
  • added more tests

Copy link
Contributor

@dsyme dsyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last set of additions please - can you also expand/multiply out your tests to include instantiations of the basic operators at the full matrix of primitive types? byte, sbyte, ..., UInt64, double, single, decimal, ... We may as well pin the whole lot down now and get everything under test?

Copy link
Contributor

@dsyme dsyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spotted a few cases where the tree being returned was inaccurate

This is extremely close to being done - I looked through everything else and it looked good.

"let testSByteToSByteOperator(e1) = Operators.ToSByte<Microsoft.FSharp.Core.sbyte> (e1) @ (42,45--42,53)";
"let testSByteToInt16Operator(e1) = Operators.ToInt16<Microsoft.FSharp.Core.sbyte> (e1) @ (43,45--43,53)";
"let testSByteToUInt16Operator(e1) = Operators.ToUInt16<Microsoft.FSharp.Core.sbyte> (e1) @ (44,45--44,54)";
"let testSByteToIntOperator(e1) = e1 @ (45,45--45,51)";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little concerned about this - it looks like the code being returned wouldn't pass type checking. This will be because it's a no-op conversion

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are quite a lot of cases of this. See comment further above in ConvExprPrim for the root cause


| TOp.ILAsm([ AI_ceq ], _), _, [arg1;arg2] ->
| TOp.ILAsm([ ], _), _, [arg] ->
ConvExprPrim cenv env arg
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case is used for no-op conversions like sbyte --> int32.

I think in this case you strictly speaking need to insert an appropriately-typed conversion operator in the F# expression based on the type of arg and the type of expr

BTW ConvExprPrim is getting kind of huge and maybe should be chopped into ConvExprPrim and ConvOpExprPrim

"let testByteToUInt64Checked(e1) = Checked.ToUInt64<Microsoft.FSharp.Core.byte> (e1) @ (37,43--37,60)";
"let testByteToIntPtrChecked(e1) = Checked.ToIntPtr<Microsoft.FSharp.Core.byte> (e1) @ (38,43--38,63)";
"let testByteToUIntPtrChecked(e1) = Checked.ToUIntPtr<Microsoft.FSharp.Core.byte> (e1) @ (39,43--39,64)";
"let testByteToByteOperator(e1) = O
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    let testInt64ToCharOperator(e1) = Operators.ToUInt16<Microsoft.FSharp.Core.int64> (e1)

This looks wrong. I think the IL instruction sequence is ambiguous and needs to be disamiguated by the type of expr in ConvExprPrim

"let testByteToUInt64Checked(e1) = Checked.ToUInt64<Microsoft.FSharp.Core.byte> (e1) @ (37,43--37,60)";
"let testByteToIntPtrChecked(e1) = Checked.ToIntPtr<Microsoft.FSharp.Core.byte> (e1) @ (38,43--38,63)";
"let testByteToUIntPtrChecked(e1) = Checked.ToUIntPtr<Microsoft.FSharp.Core.byte> (e1) @ (39,43--39,64)";
"let testByteToByteOperator(e1) = O
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's another char one where we've ended up with ToUInt16 (see comment below)

"let testByteToUInt64Checked(e1) = Checked.ToUInt64<Microsoft.FSharp.Core.byte> (e1) @ (37,43--37,60)";
"let testByteToIntPtrChecked(e1) = Checked.ToIntPtr<Microsoft.FSharp.Core.byte> (e1) @ (38,43--38,63)";
"let testByteToUIntPtrChecked(e1) = Checked.ToUIntPtr<Microsoft.FSharp.Core.byte> (e1) @ (39,43--39,64)";
"let testByteToByteOperator(e1) = O
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another char --> UInt16 mistake (See comment below)

"let testByteToUInt64Checked(e1) = Checked.ToUInt64<Microsoft.FSharp.Core.byte> (e1) @ (37,43--37,60)";
"let testByteToIntPtrChecked(e1) = Checked.ToIntPtr<Microsoft.FSharp.Core.byte> (e1) @ (38,43--38,63)";
"let testByteToUIntPtrChecked(e1) = Checked.ToUIntPtr<Microsoft.FSharp.Core.byte> (e1) @ (39,43--39,64)";
"let testByteToByteOperator(e1) = O
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another char/UInt16 mistake (See comment below)

@dsyme
Copy link
Contributor

dsyme commented Feb 14, 2018

The changes are good, thank you! Just a few warnings left I think:

  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(276,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(277,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(278,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(279,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(280,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(281,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(282,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(283,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(284,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(285,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(286,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(287,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]
  D:\j\w\debug_default---ce4d11dd\src\fsharp\symbols\Exprs.fs(288,15): error FS1182: The value 'x' is unused [D:\j\w\debug_default---ce4d11dd\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]

Copy link
Contributor

@dsyme dsyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few warnings to remove, but approved - great work on testing and thank you for going the extra distance to make this a robust feature of FCS

@ncave
Copy link
Contributor

ncave commented Feb 14, 2018

@dsyme Thank you for reviewing so thoroughly, the end result is always so much better for it.
And thank you @forki for coming up with this original idea and blazing the trail.

@forki
Copy link
Contributor Author

forki commented Feb 14, 2018 via email

@AviAvni
Copy link
Contributor

AviAvni commented Feb 14, 2018

@forki you can offer this as a service to some repos 😉

@KevinRansom KevinRansom merged commit 2180de4 into dotnet:master Feb 17, 2018
@forki
Copy link
Contributor Author

forki commented Feb 17, 2018

Awesome! This makes me happy

@realvictorprm
Copy link
Contributor

This is great! Thank you all for your work! 😃 Please take a cookie as thanks 🍪 !

"member M2(__) (unitVar1) = __.compiledAsInstanceMethod(()) @ (56,21--56,47)";
"member SM1(unitVar0) = Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (compiledAsStaticField,ClassWithImplicitConstructor.compiledAsGenericStaticMethod<Microsoft.FSharp.Core.int> (compiledAsStaticField)) @ (57,26--57,101)";
"member SM2(unitVar0) = ClassWithImplicitConstructor.compiledAsStaticMethod (()) @ (58,26--58,50)";
#if NO_PROJECTCRACKER // proxy for COMPILER
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ncave Do you recall why this was needed? I don't think it's either NO_PROJECTCRACKER nor COMPILER. I'm hitting cases where this test is now failing and I'm not sure what I've done....

Copy link
Contributor

@ncave ncave Feb 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dsyme This just means the output of FSharp.LanguageService is slightly different than FCS, and accounts for that.

These two projects reference FCS:
fcs/FSharp.Compiler.Service.Tests.netcore/FSharp.Compiler.Service.Tests.netcore.fsproj
fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj

but vsintegration/tests/unittests/VisualFSharp.UnitTests.fsproj references FSharp.LanguageService, so a symbol defined in VisualFSharp.UnitTests.fsproj is used to branch the output.

I don't know what is the error, perhaps the output is now the same? (if so, then there is no need to branch it anymore).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FSharp.LanguageService

I think you mean FSharp.Compiler.Private being used from VisualFSharp.UnitTests.fsproj

In #4368 I'm now always seeing the output in the NO_PROJECTCRACKER branch even from the two FCS test projects. I don't particularly understand why though or what's changed. Don't worry about it for now - let's see if CI passes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants