Skip to content

Do not load Path call receiver if known to be pure load#15488

Merged
straight-shoota merged 1 commit intocrystal-lang:masterfrom
HertzDevil:perf/call-receiver-path
Feb 21, 2025
Merged

Do not load Path call receiver if known to be pure load#15488
straight-shoota merged 1 commit intocrystal-lang:masterfrom
HertzDevil:perf/call-receiver-path

Conversation

@HertzDevil
Copy link
Contributor

Follow-up to #15485.

The compiler always emits LLVM instructions to load the receiver of a call even if it has a metaclass type, because there could be other side effects. This adds a large number of superfluous type ID loads when calling class methods:

  %0 = load i32, ptr @"Foo0.class:type_id", align 4
  %1 = call ptr @"*Foo0@Reference::new:Foo0"()
  %2 = load i32, ptr @"Foo1.class:type_id", align 4
  %3 = call ptr @"*Foo1@Reference::new:Foo1"()
  %4 = load i32, ptr @"Foo2.class:type_id", align 4
  %5 = call ptr @"*Foo2@Reference::new:Foo2"()
  ; ...

Although .new does load the type ID later, this ID should never show up as an implicit argument to the Foo*.new methods. Here the %0, %2, and %4 variables are a consequence of un-inlining the type IDs. This PR removes those loads when the call receiver is a Path known to refer to a non-generic metaclass type. (In isolation, the PR skips over whatever is in Crystal::CodeGenVisitor#visit(Crystal::Path).)

@straight-shoota straight-shoota added this to the 1.16.0 milestone Feb 20, 2025
@straight-shoota straight-shoota merged commit 9096870 into crystal-lang:master Feb 21, 2025
34 checks passed
@HertzDevil HertzDevil deleted the perf/call-receiver-path branch February 23, 2025 05:10
kojix2 pushed a commit to kojix2/crystal that referenced this pull request Feb 23, 2025
…15488)

The compiler always emits LLVM instructions to load the receiver of a call even if it has a metaclass type, because there could be other side effects. This adds a large number of superfluous type ID loads when calling class methods:

```llvm
  %0 = load i32, ptr @"Foo0.class:type_id", align 4
  %1 = call ptr @"*Foo0@Reference::new:Foo0"()
  %2 = load i32, ptr @"Foo1.class:type_id", align 4
  %3 = call ptr @"*Foo1@Reference::new:Foo1"()
  %4 = load i32, ptr @"Foo2.class:type_id", align 4
  %5 = call ptr @"*Foo2@Reference::new:Foo2"()
  ; ...
```

Although `.new` does load the type ID later, this ID should never show up as an implicit argument to the `Foo*.new` methods. Here the `%0`, `%2`, and `%4` variables are a consequence of un-inlining the type IDs. This patch removes those loads when the call receiver is a `Path` known to refer to a non-generic metaclass type. (In isolation, the path skips over whatever is in `Crystal::CodeGenVisitor#visit(Crystal::Path)`.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants