pasokonistan / pasopedia

https://pasopedia.pasokon.site
11 stars 2 forks source link

インラインアセンブラtips集: `memory` clobberの説明が欲しい #17

Closed kubo39 closed 9 months ago

kubo39 commented 10 months ago

memory の説明がないので、どういう意味があるのかよくわかりませんでした!! よくある __asm__ __volatile__("": : :"memory") を使ってreorderingを抑制(SW barrier)する話とかあるといいと思います!!

@Totsugekitai 先生よろしくお願いいたします!

kubo39 commented 10 months ago

Rustのasm!構文を読んでみると、デフォルトでmemory constraintを付与、かつoptionで NOMEM を指定することで外すことができるそうです。 https://doc.rust-lang.org/reference/inline-assembly.html#options

LLVM backendではこのような記述があるが、意図が汲めていない。 https://github.com/rust-lang/rust/blob/2f19122f73027219a152e0c2ff35cebab940876c/compiler/rustc_codegen_llvm/src/asm.rs#L268-L273

        if !options.contains(InlineAsmOptions::NOMEM) {
            // This is actually ignored by LLVM, but it's probably best to keep
            // it just in case. LLVM instead uses the ReadOnly/ReadNone
            // attributes on the call instruction to optimize.
            constraints.push("~{memory}".to_string());
        }
Totsugekitai commented 10 months ago

コメントありがとうございます、今週ちょっと忙しいのでもしかしたら遅くなるかもしれませんが、追記しておきたいと思います!

kubo39 commented 10 months ago

Rust and Atomicsのcompiler fenceの説明ではLLVM固有の情報には触れていない: https://marabos.nl/atomics/memory-ordering.html#compiler-fences

ただどうもLLVMは現状compiler fenceをatomic fenceにloweringするようで、これを是正するパッチが出ている(まだ本体には取り込まれていない): https://reviews.llvm.org/D92842

kubo39 commented 10 months ago

LLVM backendではこのような記述があるが、意図が汲めていない。 https://github.com/rust-lang/rust/blob/2f19122f73027219a152e0c2ff35cebab940876c/compiler/rustc_codegen_llvm/src/asm.rs#L268-L273

すぐ下に説明があった。~{memory} の有無にかかわらずデフォルトで最適化を許容しないようになっているのだな。

https://github.com/rust-lang/rust/blob/2f19122f73027219a152e0c2ff35cebab940876c/compiler/rustc_codegen_llvm/src/asm.rs#L305-L316

        if options.contains(InlineAsmOptions::PURE) {
            if options.contains(InlineAsmOptions::NOMEM) {
                attrs.push(llvm::MemoryEffects::None.create_attr(self.cx.llcx));
            } else if options.contains(InlineAsmOptions::READONLY) {
                attrs.push(llvm::MemoryEffects::ReadOnly.create_attr(self.cx.llcx));
            }
            attrs.push(llvm::AttributeKind::WillReturn.create_attr(self.cx.llcx));
        } else if options.contains(InlineAsmOptions::NOMEM) {
            attrs.push(llvm::MemoryEffects::InaccessibleMemOnly.create_attr(self.cx.llcx));
        } else {
            // LLVM doesn't have an attribute to represent ReadOnly + SideEffect
        }
        attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
kubo39 commented 10 months ago

readonly + sideeffectな最適化の組み合わせがLLVMでは提供できなくて、本来可能である最適化ができないっちゅう話かも。かなし~。

kubo39 commented 10 months ago

結論だけ書くと、LLVMのインラインアセンブラはmemory clobber(~{memory})を単に無視します。 かわりにclangやrustcなどの各処理系がいい感じに関数属性を設定(LLVMのインラインアセンブラはLLVM内部的には関数と同じ扱い)することで同等の機能を実現しています。 (ここまでpasopediaに書く必要はあるんだろうか…?)

Totsugekitai commented 10 months ago

これは驚きですね!この内容も追記していいですか? (もちろん @kubo39 さんから教えて頂いたということを明記します)

kubo39 commented 10 months ago

@Totsugekitai 大丈夫です、というかここに書いてることは自由に使ってもらってかまわないですよ。

Totsugekitai commented 10 months ago

ありがとうございます🙇

kubo39 commented 10 months ago

clobberでレジスタしかチェックしてなさそうな箇所のコード: https://github.com/llvm/llvm-project/blob/a134abf4be132cfff2fc5132d6226db919c0865b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp#L524-L537

kubo39 commented 9 months ago

fixed at #18