let OperandType = "OPERAND_LOCAL" in
def local_op : Operand<i32>;
-let OperandType = "OPERAND_GLOBAL" in
-def global_op : Operand<i32>;
+let OperandType = "OPERAND_GLOBAL" in {
+ // The operand to global instructions is always a 32-bit index.
+ def global_op32 : Operand<i32>;
+ // In PIC mode however, we temporarily represent this index as an external
+ // symbol, which to LLVM is a pointer, so in wasm64 mode it is easiest to
+ // pretend we use a 64-bit index for it.
+ def global_op64 : Operand<i64>;
+}
let OperandType = "OPERAND_I32IMM" in
def i32imm_op : Operand<i32>;
// local.get and local.set are not generated by instruction selection; they
// are implied by virtual register uses and defs.
-multiclass LOCAL<WebAssemblyRegClass vt> {
+multiclass LOCAL<WebAssemblyRegClass vt, Operand global_op> {
let hasSideEffects = 0 in {
// COPY is not an actual instruction in wasm, but since we allow local.get and
// local.set to be implicit during most of codegen, we can have a COPY which
} // hasSideEffects = 0
}
-defm "" : LOCAL<I32>;
-defm "" : LOCAL<I64>;
-defm "" : LOCAL<F32>;
-defm "" : LOCAL<F64>;
-defm "" : LOCAL<V128>, Requires<[HasSIMD128]>;
-defm "" : LOCAL<FUNCREF>, Requires<[HasReferenceTypes]>;
-defm "" : LOCAL<EXTERNREF>, Requires<[HasReferenceTypes]>;
+defm "" : LOCAL<I32, global_op32>;
+defm "" : LOCAL<I64, global_op64>; // 64-bit only needed for pointers.
+defm "" : LOCAL<F32, global_op32>;
+defm "" : LOCAL<F64, global_op32>;
+defm "" : LOCAL<V128, global_op32>, Requires<[HasSIMD128]>;
+defm "" : LOCAL<FUNCREF, global_op32>, Requires<[HasReferenceTypes]>;
+defm "" : LOCAL<EXTERNREF, global_op32>, Requires<[HasReferenceTypes]>;
let isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1 in {
defm CONST_I32 : I<(outs I32:$res), (ins i32imm_op:$imm),
def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$addr)),
(GLOBAL_GET_I32 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr32]>;
+def : Pat<(i64 (WebAssemblywrapper tglobaladdr:$addr)),
+ (GLOBAL_GET_I64 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr64]>;
def : Pat<(i32 (WebAssemblywrapperPIC tglobaladdr:$addr)),
(CONST_I32 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr32]>;
def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
(GLOBAL_GET_I32 texternalsym:$addr)>, Requires<[IsPIC, HasAddr32]>;
+def : Pat<(i64 (WebAssemblywrapper texternalsym:$addr)),
+ (GLOBAL_GET_I64 texternalsym:$addr)>, Requires<[IsPIC, HasAddr64]>;
def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
(CONST_I32 texternalsym:$addr)>, Requires<[IsNotPIC, HasAddr32]>;
-; RUN: llc < %s -asm-verbose=false -relocation-model=pic -fast-isel -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=PIC,CHECK
-; RUN: llc < %s -asm-verbose=false -relocation-model=pic -fast-isel=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=PIC,CHECK
+; RUN: llc < %s --mtriple=wasm32-unknown-emscripten -asm-verbose=false -relocation-model=pic -fast-isel -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=PIC,CHECK -DPTR=i32
+; RUN: llc < %s --mtriple=wasm32-unknown-emscripten -asm-verbose=false -relocation-model=pic -fast-isel=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=PIC,CHECK -DPTR=i32
+; RUN: llc < %s --mtriple=wasm64-unknown-emscripten -asm-verbose=false -relocation-model=pic -fast-isel -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=PIC,CHECK -DPTR=i64
+; RUN: llc < %s --mtriple=wasm64-unknown-emscripten -asm-verbose=false -relocation-model=pic -fast-isel=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=PIC,CHECK -DPTR=i64
; Test that globals assemble as expected with -fPIC.
; We test here both with and without fast-isel.
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-emscripten"
-
@hidden_global = external hidden global i32
@hidden_global_array = external hidden global [10 x i32]
@external_global = external global i32
define i32 @load_hidden_global() {
; CHECK-LABEL: load_hidden_global:
; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
-; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global@MBREL{{$}}
-; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; PIC-NEXT: [[PTR]].const $push[[L1:[0-9]+]]=, hidden_global@MBREL{{$}}
+; PIC-NEXT: [[PTR]].add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
; PIC-NEXT: i32.load $push[[L3:[0-9]+]]=, 0($pop[[L2]]){{$}}
; CHECK-NEXT: end_function
define i32 @load_hidden_global_offset() {
; CHECK-LABEL: load_hidden_global_offset:
; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
-; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global_array@MBREL{{$}}
-; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1:[0-9]+]]{{$}}
-; PIC-NEXT: i32.const $push[[L3:[0-9]+]]=, 20{{$}}
-; PIC-NEXT: i32.add $push[[L4:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; PIC-NEXT: [[PTR]].const $push[[L1:[0-9]+]]=, hidden_global_array@MBREL{{$}}
+; PIC-NEXT: [[PTR]].add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1:[0-9]+]]{{$}}
+; PIC-NEXT: [[PTR]].const $push[[L3:[0-9]+]]=, 20{{$}}
+; PIC-NEXT: [[PTR]].add $push[[L4:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
; PIC-NEXT: i32.load $push{{[0-9]+}}=, 0($pop[[L4]]){{$}}
; CHECK-NEXT: end_function
define void @store_hidden_global(i32 %n) {
; CHECK-LABEL: store_hidden_global:
; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
-; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global@MBREL{{$}}
-; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; PIC-NEXT: [[PTR]].const $push[[L1:[0-9]+]]=, hidden_global@MBREL{{$}}
+; PIC-NEXT: [[PTR]].add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
; PIC-NEXT: i32.store 0($pop[[L2]]), $0{{$}}
; CHECK-NEXT: end_function
define void @store_hidden_global_offset(i32 %n) {
; CHECK-LABEL: store_hidden_global_offset:
; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
-; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global_array@MBREL{{$}}
-; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
-; PIC-NEXT: i32.const $push[[L3:[0-9]+]]=, 20{{$}}
-; PIC-NEXT: i32.add $push[[L4:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; PIC-NEXT: [[PTR]].const $push[[L1:[0-9]+]]=, hidden_global_array@MBREL{{$}}
+; PIC-NEXT: [[PTR]].add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; PIC-NEXT: [[PTR]].const $push[[L3:[0-9]+]]=, 20{{$}}
+; PIC-NEXT: [[PTR]].add $push[[L4:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
; PIC-NEXT: i32.store 0($pop[[L4]]), $0{{$}}
; CHECK-NEXT: end_function
define i32 @load_external_global_offset() {
; CHECK-LABEL: load_external_global_offset:
; PIC: global.get $push[[L0:[0-9]+]]=, external_global_array@GOT{{$}}
-; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, 20{{$}}
-; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; PIC-NEXT: [[PTR]].const $push[[L1:[0-9]+]]=, 20{{$}}
+; PIC-NEXT: [[PTR]].add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
; PIC-NEXT: i32.load $push{{[0-9]+}}=, 0($pop[[L2]]){{$}}
; CHECK-NEXT: end_function
define void @store_external_global_offset(i32 %n) {
; CHECK-LABEL: store_external_global_offset:
; PIC: global.get $push[[L0:[0-9]+]]=, external_global_array@GOT{{$}}
-; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, 20{{$}}
-; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; PIC-NEXT: [[PTR]].const $push[[L1:[0-9]+]]=, 20{{$}}
+; PIC-NEXT: [[PTR]].add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
; PIC-NEXT: i32.store 0($pop[[L2]]), $0{{$}}
; CHECK-NEXT: end_function
ret void
}
-; PIC: .globaltype __memory_base, i32
+; PIC: .globaltype __memory_base, [[PTR]]