diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2120,6 +2120,15 @@ llvm::Type *Ty = Src->getType(); ShiftAmt = Builder.CreateIntCast(ShiftAmt, Ty, false); + // For WebAssembly we want to generate the target-specific rotate builtin, + // rather than generating fshl/fshr intrinsics. + if (getTarget().getTriple().isWasm()) { + unsigned IID = IsRotateRight ? Intrinsic::wasm_rotr_i32 + : Intrinsic::wasm_rotl_i32; + llvm::Function *F = CGM.getIntrinsic(IID); + return RValue::get(Builder.CreateCall(F, { Src, ShiftAmt })); + } + // Rotate is a special case of LLVM funnel shift - 1st 2 args are the same. unsigned IID = IsRotateRight ? Intrinsic::fshr : Intrinsic::fshl; Function *F = CGM.getIntrinsic(IID, Ty); diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -341,4 +341,16 @@ [], [IntrReadMem]>; +//===----------------------------------------------------------------------===// +// Rotate Intrinsics +// These are lowered from the target independent intrinsics to avoid +// funnel shift optimizations +//===----------------------------------------------------------------------===// + +def int_wasm_rotl_i32 : + DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; + +def int_wasm_rotr_i32 : + DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; + } // TargetPrefix = "wasm" diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td @@ -107,6 +107,12 @@ def : Pat<(rotl I64:$lhs, (and I64:$rhs, 63)), (ROTL_I64 I64:$lhs, I64:$rhs)>; def : Pat<(rotr I64:$lhs, (and I64:$rhs, 63)), (ROTR_I64 I64:$lhs, I64:$rhs)>; +// Lower the rotate intrinsic to a rotate instruction +def : Pat<(int_wasm_rotl_i32 I32:$lhs, I32:$rhs), + (ROTL_I32 I32:$lhs, I32:$rhs)>; +def : Pat<(int_wasm_rotr_i32 I32:$lhs, I32:$rhs), + (ROTR_I32 I32:$lhs, I32:$rhs)>; + defm SELECT_I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs, I32:$cond), (outs), (ins), [(set I32:$dst, (select I32:$cond, I32:$lhs, I32:$rhs))],