Skip to content
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

[Codegen][LLVM] Add ability to turn on fast math flags #9223

Merged
merged 16 commits into from Oct 19, 2021

Conversation

AndrewZhaoLuo
Copy link
Contributor

@AndrewZhaoLuo AndrewZhaoLuo commented Oct 7, 2021

Benchmarked on GCP n1-standard-4 (Broadwell) and n2-standard-4 (Cascade Lake) instances:

image

Overall broadwell had many improvements while for cascade lake there were more regressions. Runtime has been normalized by the mean of the baseline trial (without fastmath flags). Each trial was repeated with n=5

Test code:

See https://github.com/AndrewZhaoLuo/TVM-Sandbox/blob/fd08f88c12c9562a0e0f72dd7ff60f398452de35/codegen/test_export_to_ll.py#L8

"""Exporting to an LLVM assembly language file (.ll)"""

import os

import tvm
from tvm import te

if __name__ == "__main__":
    TARGET = "llvm -O=3 --fast-math"

    n = 128
    A = te.placeholder((n,), name="A", dtype="float32")
    B = te.placeholder((n,), name="B", dtype="float32")
    C = te.compute(A.shape, lambda *i: A(*i) + B(*i), name="C")
    s = tvm.te.create_schedule(C.op)
    m = tvm.lower(s, [A, B, C], name="test_add")
    rt_mod = tvm.build(m, target=TARGET)
    rt_mod.save("test.ll")

By setting the environment flag the generated LLVM ASM code is different:

Without fastmath:

; Function Attrs: nofree noinline norecurse nounwind
define internal fastcc void @test_add_compute_(i8* noalias nocapture align 128 %0, i8* noalias nocapture readonly align 128 %1, i8* noalias nocapture readonly align 128 %2) unnamed_addr #1 {
entry:
  %3 = bitcast i8* %1 to <2 x float>*
  %4 = load <2 x float>, <2 x float>* %3, align 128, !tbaa !114
  %5 = bitcast i8* %2 to <2 x float>*
  %6 = load <2 x float>, <2 x float>* %5, align 128, !tbaa !117
  %7 = fadd <2 x float> %4, %6
  %8 = bitcast i8* %0 to <2 x float>*
  store <2 x float> %7, <2 x float>* %8, align 128, !tbaa !120
  ret void
}

With fastmath:

; Function Attrs: nofree noinline norecurse nounwind
define internal fastcc void @test_add_compute_(i8* noalias nocapture align 128 %0, i8* noalias nocapture readonly align 128 %1, i8* noalias nocapture readonly align 128 %2) unnamed_addr #1 {
entry:
  %3 = bitcast i8* %1 to <2 x float>*
  %4 = load <2 x float>, <2 x float>* %3, align 128, !tbaa !114
  %5 = bitcast i8* %2 to <2 x float>*
  %6 = load <2 x float>, <2 x float>* %5, align 128, !tbaa !117
  %7 = fadd fast <2 x float> %6, %4
  %8 = bitcast i8* %0 to <2 x float>*
  store <2 x float> %7, <2 x float>* %8, align 128, !tbaa !120
  ret void
}

Note the fast tag to the fadd operations now.

@masahi
Copy link
Member

masahi commented Oct 8, 2021

I think it is better to make use of a target attribute, e.g. target = "llvm -fastmath"

@AndrewZhaoLuo AndrewZhaoLuo changed the title [WIP][Codegen][LLVM] Add ability to turn on fast math flags [Codegen][LLVM] Add ability to turn on fast math flags Oct 12, 2021
@AndrewZhaoLuo AndrewZhaoLuo marked this pull request as ready for review October 12, 2021 22:36
@AndrewZhaoLuo
Copy link
Contributor Author

This is ready for review now

// semantics. These just enable these optimizations if the proper IR flags
// are set.
opt.UnsafeFPMath = true;
opt.NoInfsFPMath = true;
Copy link
Member

Choose a reason for hiding this comment

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

Better not to change the default values unless there is a good reason.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need to look deeper at the LLVM code, but I think these optimization respect "fastmath" flags. So if we turn these optimizations on and run it on generated IR without fastmath flags, it should have the same behavior as before.

But yes, let me double check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, yes these settings in Clang are passed in from LangOpts which describe the dialect of C or C++ that is accepted. Don't understand it fully and don't want to change the specification here so turned it off.

llvm::TargetMachine* tm =
llvm_target->createTargetMachine(target_triple, mcpu, mattr, opt, llvm::Reloc::PIC_);

Integer llvm_opt_level = target->GetAttr<Integer>("O").value_or(Integer(2));
Copy link
Member

@masahi masahi Oct 14, 2021

Choose a reason for hiding this comment

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

See

builder.OptLevel = 3;
. I think they refer to the same opt level.

I don't see why users would want to choose an opt level other than 3. However, internally we may want to prefer faster compile time for the constant folding use case (which currently compiles every subgraph with opt level = 3).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm good catch. Need to see what the difference between the two optimization settings is.

As for the right Opt-Level, I think 3 can lead to slow downs in some situations (granted this is about gcc but same idea):
https://wiki.gentoo.org/wiki/GCC_optimization#-O

-O3: the highest level of optimization possible. It enables optimizations that are expensive in terms of compile time and memory usage. Compiling with -O3 is not a guaranteed way to improve performance, and in fact, in many cases, can slow down a system due to larger binaries and increased memory usage. -O3 is also known to break several packages. Using -O3 is not recommended. However, it also enables -ftree-vectorize so that loops in the code get vectorized and will use AVX YMM registers.

I did run a trial of fast math + changes the TargetMachine opt level to O2 and some models were faster and some were slower.

So we should add the flag to make it easy to test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm so the link listed is for the PassManager. Higher opt level = more passes much like we have relay opt level. It appears to be associated with -O3 in clang. However, CodeGenOpts appears to be a separate thing that is set in clang too https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/BackendUtil.cpp#L935. Looks like this emits the assembly. This is also associated with clang's -O3.

So the flag should control everything.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I made it based on the -O flag added. Default is still 2 however (which is the default for clang I believe)

@AndrewZhaoLuo
Copy link
Contributor Author

PTAL @masahi


default:
// CodeGenOpt::Level::Aggressive
builder.OptLevel = 3;
Copy link
Member

Choose a reason for hiding this comment

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

A related comment: This code path should hit by default, otherwise this change would introduce regression.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, I see fair enough, I think OptLevel 3 should not be the default but let me get some data to support this first. Changed to make OptLevel 3 the default.

Copy link
Member

Choose a reason for hiding this comment

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

I think we just inherited opt level being 3 by default from Halide: https://github.com/halide/Halide/blob/ed87acb466f13144be235a33a30f242e30a6a74f/src/CodeGen_LLVM.cpp#L1145

@masahi
Copy link
Member

masahi commented Oct 18, 2021

@AndrewZhaoLuo I think -O=3 syntax is weird, how about -opt-level=3?

@AndrewZhaoLuo
Copy link
Contributor Author

Done, renamed -O --> -opt-level

@masahi
Copy link
Member

masahi commented Oct 18, 2021

@masahi masahi merged commit f095595 into apache:main Oct 19, 2021
ccjoechou pushed a commit to ccjoechou/tvm that referenced this pull request Oct 19, 2021
* flags to turn off and on

* turn fast math on always

* llvm more opts

* move to default codegen opt

* TODO

* add fast math options to llvm target

* move to using new target attributes

* llvm fast math target opt code

* add -O flags

* fix todo lint

* support llvm 4.0, 5.0

* use same opt level as target machine

* revert TargetOptions

* fix thing

* prevent regression in llvm

* togglable opt-levels

Co-authored-by: Andrew Zhao Luo <andrewzhaoluo@system76-pc.localdomain>
ylc pushed a commit to ylc/tvm that referenced this pull request Jan 7, 2022
* flags to turn off and on

* turn fast math on always

* llvm more opts

* move to default codegen opt

* TODO

* add fast math options to llvm target

* move to using new target attributes

* llvm fast math target opt code

* add -O flags

* fix todo lint

* support llvm 4.0, 5.0

* use same opt level as target machine

* revert TargetOptions

* fix thing

* prevent regression in llvm

* togglable opt-levels

Co-authored-by: Andrew Zhao Luo <andrewzhaoluo@system76-pc.localdomain>
ylc pushed a commit to ylc/tvm that referenced this pull request Jan 13, 2022
* flags to turn off and on

* turn fast math on always

* llvm more opts

* move to default codegen opt

* TODO

* add fast math options to llvm target

* move to using new target attributes

* llvm fast math target opt code

* add -O flags

* fix todo lint

* support llvm 4.0, 5.0

* use same opt level as target machine

* revert TargetOptions

* fix thing

* prevent regression in llvm

* togglable opt-levels

Co-authored-by: Andrew Zhao Luo <andrewzhaoluo@system76-pc.localdomain>
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.

None yet

2 participants