View Issue Details

IDProjectCategoryView StatusLast Update
0023862FPCCompilerpublic2015-12-09 16:33
ReporterMaciej Izak Assigned ToFlorian  
PrioritynormalSeverityfeatureReproducibilityalways
Status resolvedResolutionfixed 
Product Version2.7.1 
Fixed in Version3.0.1 
Summary0023862: Inline and "Procedure too complex, it requires too many registers"
DescriptionCan't compile attached unit (in Delphi it's ok).

When I delete all inline keywords from unit it's compile.
TagsNo tags attached.
Fixed in Revision32621
FPCOldBugId
FPCTarget
Attached Files

Relationships

related to 0027206 resolvedSven Barth [Patch] Christmas gift by FreeSparta : Generics.Collections 

Activities

Maciej Izak

2013-02-08 21:17

reporter  

Thaddy de Koning

2013-02-09 12:54

reporter   ~0065593

If you open the cpu window in Delphi, is it actually inlined? Because inline is a compiler hint, i.e. try to inline in Delphi - but do not if it is not possible -, not a compiler *must* inline.

Maciej Izak

2013-02-10 11:23

reporter   ~0065615

Yes, for example any function in function TAnyValue.Equal in "case FValueType of" is inlined (checked in Delphi XE2 cpu window). In FPC i have fatal error for the same function (TAnyValue.Equal):

Cromis.AnyValue.pas(947,44) Fatal: Procedure too complex, it requires too many registers

Zeljan Rikalo

2014-01-14 17:25

reporter   ~0072430

Even without any inline 2.6.2 dies on macosx with long procedure .... eg:
AList: TStringList;
begin
  AList := TStringList.Create;
  with AList do
  begin
    Add('Some string .......');
    Add('Some string .......xxxxxxxxxxxxxxxxxxxxxxxx');
    Add('Some string .......yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy');
    // ...etc... cca 10000 Add() with const string
    // 2.6.2 on mac intel stops with "Fatal: Procedure too complex, it requires too many registers" ... while linux/win works fine
  end;
  AList.Free;
end;

Jonas Maebe

2014-01-14 20:04

manager   ~0072434

That's because on Mac OS X, by default PIC code is generated (because it's required by shared libraries, and since OS X 10.9 also for executables submitted to the AppStore), which requires more registers. If you make it even more complex or compile explicitly with -Cg, it will also fail on Linux.

In general, the only thing you can do is split up the procedure, it's a limitation of the register allocator. The upper limit for virtual registers may be increased in the future at some point, but it's not considered to be a critical problem.

Zeljan Rikalo

2014-01-19 11:42

reporter   ~0072537

I did it already (splitted proc) ... thanks.

Sergei Gorelkin

2014-01-19 14:35

developer   ~0072541

This issue is a classic case of "entity expansion attack". With every procedure declared as inline and calling several other inlined procedures, the total amount of inline expansions grows exponentially and any complexity limit can be reached very fast.

The compiler needs mechanism to limit the inlining depth/complexity.

Florian

2014-01-19 16:15

administrator   ~0072545

Actually, I though it limits inline expansion depth?

Jonas Maebe

2014-01-19 17:23

manager   ~0072548

Only for recursive calls: an inlined routine cannot get inlined again into itself.

Sergei Gorelkin

2014-01-19 17:33

developer   ~0072549

Last edited: 2014-01-19 17:34

View 2 revisions

In response to Florian's question:
I couldn't find any code responsible for that.
(At first, I thought it enters an infinite loop with A inlining B and B inlining A. But fortunately forward calls to functions from same unit are not inlined, because compiler had not yet parsed body of following functions. However it can be possible to trigger infinite recursion scenario using two units.)

Jonas Maebe

2014-01-19 17:40

manager   ~0072550

> However it can be possible to trigger infinite recursion scenario using two units.

No, because the po_inline flag is unset while processing the inlined body of a function (ncal.pas:4130)

Marco van de Voort

2015-01-13 16:01

manager   ~0080348

Maybe make a limit on expansion depth weighted? IOW from a non-inlined procedure you can only inline a certain weight, and if that is reached (directly or indirectly) it stops inlining?

The advantage would be that cheap (oneliner) functions are treated more leniently, while they probably yield the largest benefit, and the least register pressure?

And if a complex procedure does match the left over weight, some simple procedure might still be inlined.

Jonas Maebe

2015-01-13 18:08

manager   ~0080356

Florian has been working on an auto-inlining patch from time to time. That's unrelated to this problem though, and even with limitations you could still easily run into the limit of the register allocator.

Florian

2015-01-17 14:55

administrator   ~0080468

I have implemented a patch which prevents limits code grow by inline expansion which fixes this example. Nevertheless, one can still construct examples which trigger again the "procedure too complex error", but it should be harder which "real world"-code now.

Issue History

Date Modified Username Field Change
2013-02-08 21:17 Maciej Izak New Issue
2013-02-08 21:17 Maciej Izak File Added: Cromis.AnyValue.pas.zip
2013-02-09 12:54 Thaddy de Koning Note Added: 0065593
2013-02-10 11:23 Maciej Izak Note Added: 0065615
2014-01-14 17:25 Zeljan Rikalo Note Added: 0072430
2014-01-14 20:04 Jonas Maebe Note Added: 0072434
2014-01-14 20:04 Jonas Maebe Priority high => normal
2014-01-14 20:04 Jonas Maebe Severity crash => feature
2014-01-19 11:42 Zeljan Rikalo Note Added: 0072537
2014-01-19 14:35 Sergei Gorelkin Note Added: 0072541
2014-01-19 16:15 Florian Note Added: 0072545
2014-01-19 17:23 Jonas Maebe Note Added: 0072548
2014-01-19 17:33 Sergei Gorelkin Note Added: 0072549
2014-01-19 17:34 Sergei Gorelkin Note Edited: 0072549 View Revisions
2014-01-19 17:40 Jonas Maebe Note Added: 0072550
2015-01-06 21:56 Sven Barth Relationship added related to 0027206
2015-01-13 16:01 Marco van de Voort Note Added: 0080348
2015-01-13 18:08 Jonas Maebe Note Added: 0080356
2015-01-17 14:55 Florian Fixed in Revision => 29495
2015-01-17 14:55 Florian Note Added: 0080468
2015-01-17 14:55 Florian Status new => resolved
2015-01-17 14:55 Florian Fixed in Version => 3.1.1
2015-01-17 14:55 Florian Resolution open => fixed
2015-01-17 14:55 Florian Assigned To => Florian
2015-12-09 16:33 Jonas Maebe Fixed in Revision 29495 => 32621
2015-12-09 16:33 Jonas Maebe Fixed in Version 3.1.1 => 3.0.1