[llvm] dce25be - [WebAssembly][GlobalISel] Implement `COPY` (#197256)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 30 00:33:17 PDT 2026
Author: Demetrius Kanios
Date: 2026-06-30T00:33:12-07:00
New Revision: dce25be9ad415ec18b160db3379490cb2bd260e8
URL: https://github.com/llvm/llvm-project/commit/dce25be9ad415ec18b160db3379490cb2bd260e8
DIFF: https://github.com/llvm/llvm-project/commit/dce25be9ad415ec18b160db3379490cb2bd260e8.diff
LOG: [WebAssembly][GlobalISel] Implement `COPY` (#197256)
Adds instruction select handling and tests for `COPY`. While `COPY` gets
dissolved in the end, these changes are required to keep the selector
from crashing when trying to assign a regclass to its operands.
Split from #157161
Added:
llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/copy.mir
Modified:
llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp
llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp
index 5c27dd9b5b201..2331b8b636603 100644
--- a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp
+++ b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyInstructionSelector.cpp
@@ -46,6 +46,7 @@ class WebAssemblyInstructionSelector : public InstructionSelector {
private:
bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
+ bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
const WebAssemblyTargetMachine &TM;
// const WebAssemblySubtarget &STI;
@@ -83,13 +84,68 @@ WebAssemblyInstructionSelector::WebAssemblyInstructionSelector(
{
}
+bool WebAssemblyInstructionSelector::selectCopy(
+ MachineInstr &I, MachineRegisterInfo &MRI) const {
+ const TargetRegisterClass *DstRC =
+ TRI.getConstrainedRegClassForOperand(I.getOperand(0), MRI);
+ if (!DstRC)
+ return false;
+
+ const TargetRegisterClass *SrcRC =
+ TRI.getConstrainedRegClassForOperand(I.getOperand(1), MRI);
+ if (!SrcRC)
+ return false;
+
+ Register DstReg = I.getOperand(0).getReg();
+ Register SrcReg = I.getOperand(1).getReg();
+
+ if (DstReg.isVirtual())
+ RBI.constrainGenericRegister(DstReg, *DstRC, MRI);
+ if (SrcReg.isVirtual())
+ RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI);
+
+ if (DstRC != SrcRC) {
+ if (DstReg.isPhysical() || SrcReg.isPhysical())
+ llvm_unreachable("COPY to/from SP[32/64] or FP[32/64] with mismatching "
+ "classes not currently supported");
+
+ if (DstRC == &WebAssembly::I32RegClass &&
+ SrcRC == &WebAssembly::F32RegClass) {
+ I.setDesc(TII.get(WebAssembly::I32_REINTERPRET_F32));
+ return true;
+ }
+ if (DstRC == &WebAssembly::F32RegClass &&
+ SrcRC == &WebAssembly::I32RegClass) {
+ I.setDesc(TII.get(WebAssembly::F32_REINTERPRET_I32));
+ return true;
+ }
+ if (DstRC == &WebAssembly::I64RegClass &&
+ SrcRC == &WebAssembly::F64RegClass) {
+ I.setDesc(TII.get(WebAssembly::I64_REINTERPRET_F64));
+ return true;
+ }
+ if (DstRC == &WebAssembly::F64RegClass &&
+ SrcRC == &WebAssembly::I64RegClass) {
+ I.setDesc(TII.get(WebAssembly::F64_REINTERPRET_I64));
+ return true;
+ }
+
+ llvm_unreachable("COPY between unsupported reg classes.");
+ }
+
+ return true;
+}
+
bool WebAssemblyInstructionSelector::select(MachineInstr &I) {
MachineBasicBlock &MBB = *I.getParent();
MachineFunction &MF = *MBB.getParent();
MachineRegisterInfo &MRI = MF.getRegInfo();
- if (!I.isPreISelOpcode())
+ if (!I.isPreISelOpcode()) {
+ if (I.isCopy())
+ return selectCopy(I, MRI);
return true;
+ }
if (selectImpl(I, *CoverageInfo))
return true;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp
index 4b4f07bd782ad..0c8241461f805 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp
@@ -184,8 +184,23 @@ WebAssemblyRegisterInfo::getConstrainedRegClassForOperand(
const MachineOperand &MO, const MachineRegisterInfo &MRI) const {
assert(MO.isReg());
- const RegClassOrRegBank &RegClassOrBank =
- MRI.getRegClassOrRegBank(MO.getReg());
+ Register Reg = MO.getReg();
+
+ if (Reg.isPhysical()) {
+ switch (Reg.id()) {
+ case WebAssembly::SP32:
+ case WebAssembly::FP32:
+ return &WebAssembly::I32RegClass;
+ case WebAssembly::SP64:
+ case WebAssembly::FP64:
+ return &WebAssembly::I64RegClass;
+ break;
+ default:
+ return nullptr;
+ }
+ }
+
+ const RegClassOrRegBank &RegClassOrBank = MRI.getRegClassOrRegBank(Reg);
if (RegClassOrBank.isNull())
return nullptr;
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/copy.mir b/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/copy.mir
new file mode 100644
index 0000000000000..a692af7437071
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/copy.mir
@@ -0,0 +1,294 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=wasm32-unknown-unknown -run-pass=regbankselect,instruction-select %s -o - | FileCheck %s
+
+---
+name: copy_i32
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_i32
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32 = ARGUMENT_i32 0, implicit $arguments
+ ; CHECK-NEXT: RETURN [[ARGUMENT_i32_]], implicit-def $arguments
+ %0:i32(i32) = ARGUMENT_i32 0, implicit $arguments
+ %1:_(i32) = COPY %0(i32)
+ RETURN %1(i32), implicit-def $arguments
+...
+
+---
+name: copy_i64
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_i64
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_i64_:%[0-9]+]]:i64 = ARGUMENT_i64 0, implicit $arguments
+ ; CHECK-NEXT: RETURN [[ARGUMENT_i64_]], implicit-def $arguments
+ %0:i64(i64) = ARGUMENT_i64 0, implicit $arguments
+ %1:_(i64) = COPY %0(i64)
+ RETURN %1(i64), implicit-def $arguments
+...
+
+---
+name: copy_f32
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_f32
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_f32_:%[0-9]+]]:f32 = ARGUMENT_f32 0, implicit $arguments
+ ; CHECK-NEXT: RETURN [[ARGUMENT_f32_]], implicit-def $arguments
+ %0:f32(f32) = ARGUMENT_f32 0, implicit $arguments
+ %1:_(f32) = COPY %0(f32)
+ RETURN %1(f32), implicit-def $arguments
+...
+
+---
+name: copy_f64
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_f64
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_f64_:%[0-9]+]]:f64 = ARGUMENT_f64 0, implicit $arguments
+ ; CHECK-NEXT: RETURN [[ARGUMENT_f64_]], implicit-def $arguments
+ %0:f64(f64) = ARGUMENT_f64 0, implicit $arguments
+ %1:_(f64) = COPY %0(f64)
+ RETURN %1(f64), implicit-def $arguments
+...
+
+---
+name: copy_to_sp32
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_to_sp32
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32 = ARGUMENT_i32 0, implicit $arguments
+ ; CHECK-NEXT: $sp32 = COPY [[ARGUMENT_i32_]]
+ ; CHECK-NEXT: RETURN implicit-def $arguments
+ %0:i32(i32) = ARGUMENT_i32 0, implicit $arguments
+ $sp32 = COPY %0(i32)
+ RETURN implicit-def $arguments
+...
+
+---
+name: copy_to_sp64
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_to_sp64
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_i64_:%[0-9]+]]:i64 = ARGUMENT_i64 0, implicit $arguments
+ ; CHECK-NEXT: $sp64 = COPY [[ARGUMENT_i64_]]
+ ; CHECK-NEXT: RETURN implicit-def $arguments
+ %0:i64(i64) = ARGUMENT_i64 0, implicit $arguments
+ $sp64 = COPY %0(i64)
+ RETURN implicit-def $arguments
+...
+
+---
+name: copy_from_sp32
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_from_sp32
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:i32 = COPY $sp32
+ ; CHECK-NEXT: RETURN [[COPY]], implicit-def $arguments
+ %0:_(i32) = COPY $sp32
+ RETURN %0(i32), implicit-def $arguments
+...
+
+---
+name: copy_from_sp64
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_from_sp64
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:i64 = COPY $sp64
+ ; CHECK-NEXT: RETURN [[COPY]], implicit-def $arguments
+ %0:_(i64) = COPY $sp64
+ RETURN %0(i64), implicit-def $arguments
+...
+
+---
+name: copy_to_fp32
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_to_fp32
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32 = ARGUMENT_i32 0, implicit $arguments
+ ; CHECK-NEXT: $fp32 = COPY [[ARGUMENT_i32_]]
+ ; CHECK-NEXT: RETURN implicit-def $arguments
+ %0:i32(i32) = ARGUMENT_i32 0, implicit $arguments
+ $fp32 = COPY %0(i32)
+ RETURN implicit-def $arguments
+...
+
+---
+name: copy_to_fp64
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_to_fp64
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_i64_:%[0-9]+]]:i64 = ARGUMENT_i64 0, implicit $arguments
+ ; CHECK-NEXT: $fp64 = COPY [[ARGUMENT_i64_]]
+ ; CHECK-NEXT: RETURN implicit-def $arguments
+ %0:i64(i64) = ARGUMENT_i64 0, implicit $arguments
+ $fp64 = COPY %0(i64)
+ RETURN implicit-def $arguments
+...
+
+---
+name: copy_from_fp32
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_from_fp32
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:i32 = COPY $fp32
+ ; CHECK-NEXT: RETURN [[COPY]], implicit-def $arguments
+ %0:_(i32) = COPY $fp32
+ RETURN %0(i32), implicit-def $arguments
+...
+
+---
+name: copy_from_fp64
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_from_fp64
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:i64 = COPY $fp64
+ ; CHECK-NEXT: RETURN [[COPY]], implicit-def $arguments
+ %0:_(i64) = COPY $fp64
+ RETURN %0(i64), implicit-def $arguments
+...
+
+---
+name: copy_i32_to_f32
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_i32_to_f32
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32 = ARGUMENT_i32 0, implicit $arguments
+ ; CHECK-NEXT: [[F32_REINTERPRET_I32_:%[0-9]+]]:f32 = F32_REINTERPRET_I32 [[ARGUMENT_i32_]]
+ ; CHECK-NEXT: RETURN [[F32_REINTERPRET_I32_]], implicit-def $arguments
+ %0:i32 = ARGUMENT_i32 0, implicit $arguments
+ %1:f32 = COPY %0
+ RETURN %1, implicit-def $arguments
+...
+
+---
+name: copy_f32_to_i32
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_f32_to_i32
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_f32_:%[0-9]+]]:f32 = ARGUMENT_f32 0, implicit $arguments
+ ; CHECK-NEXT: [[I32_REINTERPRET_F32_:%[0-9]+]]:i32 = I32_REINTERPRET_F32 [[ARGUMENT_f32_]]
+ ; CHECK-NEXT: RETURN [[I32_REINTERPRET_F32_]], implicit-def $arguments
+ %0:f32 = ARGUMENT_f32 0, implicit $arguments
+ %1:i32 = COPY %0
+ RETURN %1, implicit-def $arguments
+...
+
+---
+name: copy_i64_to_f64
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_i64_to_f64
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_i64_:%[0-9]+]]:i64 = ARGUMENT_i64 0, implicit $arguments
+ ; CHECK-NEXT: [[F64_REINTERPRET_I64_:%[0-9]+]]:f64 = F64_REINTERPRET_I64 [[ARGUMENT_i64_]]
+ ; CHECK-NEXT: RETURN [[F64_REINTERPRET_I64_]], implicit-def $arguments
+ %0:i64 = ARGUMENT_i64 0, implicit $arguments
+ %1:f64 = COPY %0
+ RETURN %1, implicit-def $arguments
+...
+
+---
+name: copy_f64_to_f64
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.1.entry:
+ liveins: $arguments
+
+ ; CHECK-LABEL: name: copy_f64_to_f64
+ ; CHECK: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ARGUMENT_f64_:%[0-9]+]]:f64 = ARGUMENT_f64 0, implicit $arguments
+ ; CHECK-NEXT: [[I64_REINTERPRET_F64_:%[0-9]+]]:i64 = I64_REINTERPRET_F64 [[ARGUMENT_f64_]]
+ ; CHECK-NEXT: RETURN [[I64_REINTERPRET_F64_]], implicit-def $arguments
+ %0:f64 = ARGUMENT_f64 0, implicit $arguments
+ %1:i64 = COPY %0
+ RETURN %1, implicit-def $arguments
+...
More information about the llvm-commits
mailing list