| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| //=- WebAssemblySetP2AlignOperands.cpp - Set alignments on loads and stores -=// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| /// | ||
| /// \file | ||
| /// \brief This file sets the p2align operands on load and store instructions. | ||
| /// | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "WebAssembly.h" | ||
| #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" | ||
| #include "WebAssemblyMachineFunctionInfo.h" | ||
| #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" | ||
| #include "llvm/CodeGen/MachineMemOperand.h" | ||
| #include "llvm/CodeGen/Passes.h" | ||
| #include "llvm/Support/Debug.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "wasm-set-p2align-operands" | ||
|
|
||
| namespace { | ||
| class WebAssemblySetP2AlignOperands final : public MachineFunctionPass { | ||
| public: | ||
| static char ID; // Pass identification, replacement for typeid | ||
| WebAssemblySetP2AlignOperands() : MachineFunctionPass(ID) {} | ||
|
|
||
| const char *getPassName() const override { | ||
| return "WebAssembly Set p2align Operands"; | ||
| } | ||
|
|
||
| void getAnalysisUsage(AnalysisUsage &AU) const override { | ||
| AU.setPreservesCFG(); | ||
| AU.addPreserved<MachineBlockFrequencyInfo>(); | ||
| AU.addPreservedID(MachineDominatorsID); | ||
| MachineFunctionPass::getAnalysisUsage(AU); | ||
| } | ||
|
|
||
| bool runOnMachineFunction(MachineFunction &MF) override; | ||
| }; | ||
| } // end anonymous namespace | ||
|
|
||
| char WebAssemblySetP2AlignOperands::ID = 0; | ||
| FunctionPass *llvm::createWebAssemblySetP2AlignOperands() { | ||
| return new WebAssemblySetP2AlignOperands(); | ||
| } | ||
|
|
||
| bool WebAssemblySetP2AlignOperands::runOnMachineFunction(MachineFunction &MF) { | ||
| DEBUG({ | ||
| dbgs() << "********** Set p2align Operands **********\n" | ||
| << "********** Function: " << MF.getName() << '\n'; | ||
| }); | ||
|
|
||
| bool Changed = false; | ||
|
|
||
| for (auto &MBB : MF) { | ||
| for (auto &MI : MBB) { | ||
| switch (MI.getOpcode()) { | ||
| case WebAssembly::LOAD_I32: | ||
| case WebAssembly::LOAD_I64: | ||
| case WebAssembly::LOAD_F32: | ||
| case WebAssembly::LOAD_F64: | ||
| case WebAssembly::LOAD8_S_I32: | ||
| case WebAssembly::LOAD8_U_I32: | ||
| case WebAssembly::LOAD16_S_I32: | ||
| case WebAssembly::LOAD16_U_I32: | ||
| case WebAssembly::LOAD8_S_I64: | ||
| case WebAssembly::LOAD8_U_I64: | ||
| case WebAssembly::LOAD16_S_I64: | ||
| case WebAssembly::LOAD16_U_I64: | ||
| case WebAssembly::LOAD32_S_I64: | ||
| case WebAssembly::LOAD32_U_I64: | ||
| case WebAssembly::STORE_I32: | ||
| case WebAssembly::STORE_I64: | ||
| case WebAssembly::STORE_F32: | ||
| case WebAssembly::STORE_F64: | ||
| case WebAssembly::STORE8_I32: | ||
| case WebAssembly::STORE16_I32: | ||
| case WebAssembly::STORE8_I64: | ||
| case WebAssembly::STORE16_I64: | ||
| case WebAssembly::STORE32_I64: | ||
| assert(MI.getOperand(3).getImm() == 0 && | ||
| "ISel should set p2align operands to 0"); | ||
| assert(MI.hasOneMemOperand() && | ||
| "Load and store instructions have exactly one mem operand"); | ||
| assert((*MI.memoperands_begin())->getSize() == | ||
| (UINT64_C(1) | ||
| << WebAssembly::GetDefaultP2Align(MI.getOpcode())) && | ||
| "Default p2align value should be natural"); | ||
| assert(MI.getDesc().OpInfo[3].OperandType == | ||
| WebAssembly::OPERAND_P2ALIGN && | ||
| "Load and store instructions should have a p2align operand"); | ||
| MI.getOperand(3).setImm( | ||
| Log2_64((*MI.memoperands_begin())->getAlignment())); | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return Changed; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,210 @@ | ||
| ; RUN: llc < %s -asm-verbose=false | FileCheck %s | ||
|
|
||
| ; Test loads and stores with custom alignment values. | ||
|
|
||
| target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" | ||
| target triple = "wasm32-unknown-unknown" | ||
|
|
||
| ; CHECK-LABEL: ldi32_a1: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i32{{$}} | ||
| ; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i32 @ldi32_a1(i32 *%p) { | ||
| %v = load i32, i32* %p, align 1 | ||
| ret i32 %v | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi32_a2: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i32{{$}} | ||
| ; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i32 @ldi32_a2(i32 *%p) { | ||
| %v = load i32, i32* %p, align 2 | ||
| ret i32 %v | ||
| } | ||
|
|
||
| ; 4 is the default alignment for i32 so no attribute is needed. | ||
|
|
||
| ; CHECK-LABEL: ldi32_a4: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i32{{$}} | ||
| ; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i32 @ldi32_a4(i32 *%p) { | ||
| %v = load i32, i32* %p, align 4 | ||
| ret i32 %v | ||
| } | ||
|
|
||
| ; The default alignment in LLVM is the same as the defualt alignment in wasm. | ||
|
|
||
| ; CHECK-LABEL: ldi32: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i32{{$}} | ||
| ; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i32 @ldi32(i32 *%p) { | ||
| %v = load i32, i32* %p | ||
| ret i32 %v | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi32_a8: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i32{{$}} | ||
| ; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0):p2align=3{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i32 @ldi32_a8(i32 *%p) { | ||
| %v = load i32, i32* %p, align 8 | ||
| ret i32 %v | ||
| } | ||
|
|
||
| ; Extending loads. | ||
|
|
||
| ; CHECK-LABEL: ldi8_a1: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i32{{$}} | ||
| ; CHECK-NEXT: i32.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i8 @ldi8_a1(i8 *%p) { | ||
| %v = load i8, i8* %p, align 1 | ||
| ret i8 %v | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi8_a2: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i32{{$}} | ||
| ; CHECK-NEXT: i32.load8_u $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i8 @ldi8_a2(i8 *%p) { | ||
| %v = load i8, i8* %p, align 2 | ||
| ret i8 %v | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi16_a1: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i32{{$}} | ||
| ; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i16 @ldi16_a1(i16 *%p) { | ||
| %v = load i16, i16* %p, align 1 | ||
| ret i16 %v | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi16_a2: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i32{{$}} | ||
| ; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i16 @ldi16_a2(i16 *%p) { | ||
| %v = load i16, i16* %p, align 2 | ||
| ret i16 %v | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi16_a4: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i32{{$}} | ||
| ; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=2{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i16 @ldi16_a4(i16 *%p) { | ||
| %v = load i16, i16* %p, align 4 | ||
| ret i16 %v | ||
| } | ||
|
|
||
| ; Stores. | ||
|
|
||
| ; CHECK-LABEL: sti32_a1: | ||
| ; CHECK-NEXT: .param i32, i32{{$}} | ||
| ; CHECK-NEXT: i32.store $discard=, 0($0):p2align=0, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti32_a1(i32 *%p, i32 %v) { | ||
| store i32 %v, i32* %p, align 1 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti32_a2: | ||
| ; CHECK-NEXT: .param i32, i32{{$}} | ||
| ; CHECK-NEXT: i32.store $discard=, 0($0):p2align=1, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti32_a2(i32 *%p, i32 %v) { | ||
| store i32 %v, i32* %p, align 2 | ||
| ret void | ||
| } | ||
|
|
||
| ; 4 is the default alignment for i32 so no attribute is needed. | ||
|
|
||
| ; CHECK-LABEL: sti32_a4: | ||
| ; CHECK-NEXT: .param i32, i32{{$}} | ||
| ; CHECK-NEXT: i32.store $discard=, 0($0), $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti32_a4(i32 *%p, i32 %v) { | ||
| store i32 %v, i32* %p, align 4 | ||
| ret void | ||
| } | ||
|
|
||
| ; The default alignment in LLVM is the same as the defualt alignment in wasm. | ||
|
|
||
| ; CHECK-LABEL: sti32: | ||
| ; CHECK-NEXT: .param i32, i32{{$}} | ||
| ; CHECK-NEXT: i32.store $discard=, 0($0), $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti32(i32 *%p, i32 %v) { | ||
| store i32 %v, i32* %p | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti32_a8: | ||
| ; CHECK-NEXT: .param i32, i32{{$}} | ||
| ; CHECK-NEXT: i32.store $discard=, 0($0):p2align=3, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti32_a8(i32 *%p, i32 %v) { | ||
| store i32 %v, i32* %p, align 8 | ||
| ret void | ||
| } | ||
|
|
||
| ; Truncating stores. | ||
|
|
||
| ; CHECK-LABEL: sti8_a1: | ||
| ; CHECK-NEXT: .param i32, i32{{$}} | ||
| ; CHECK-NEXT: i32.store8 $discard=, 0($0), $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti8_a1(i8 *%p, i8 %v) { | ||
| store i8 %v, i8* %p, align 1 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti8_a2: | ||
| ; CHECK-NEXT: .param i32, i32{{$}} | ||
| ; CHECK-NEXT: i32.store8 $discard=, 0($0):p2align=1, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti8_a2(i8 *%p, i8 %v) { | ||
| store i8 %v, i8* %p, align 2 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti16_a1: | ||
| ; CHECK-NEXT: .param i32, i32{{$}} | ||
| ; CHECK-NEXT: i32.store16 $discard=, 0($0):p2align=0, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti16_a1(i16 *%p, i16 %v) { | ||
| store i16 %v, i16* %p, align 1 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti16_a2: | ||
| ; CHECK-NEXT: .param i32, i32{{$}} | ||
| ; CHECK-NEXT: i32.store16 $discard=, 0($0), $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti16_a2(i16 *%p, i16 %v) { | ||
| store i16 %v, i16* %p, align 2 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti16_a4: | ||
| ; CHECK-NEXT: .param i32, i32{{$}} | ||
| ; CHECK-NEXT: i32.store16 $discard=, 0($0):p2align=2, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti16_a4(i16 *%p, i16 %v) { | ||
| store i16 %v, i16* %p, align 4 | ||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,323 @@ | ||
| ; RUN: llc < %s -asm-verbose=false | FileCheck %s | ||
|
|
||
| ; Test loads and stores with custom alignment values. | ||
|
|
||
| target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" | ||
| target triple = "wasm32-unknown-unknown" | ||
|
|
||
| ; CHECK-LABEL: ldi64_a1: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi64_a1(i64 *%p) { | ||
| %v = load i64, i64* %p, align 1 | ||
| ret i64 %v | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi64_a2: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi64_a2(i64 *%p) { | ||
| %v = load i64, i64* %p, align 2 | ||
| ret i64 %v | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi64_a4: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=2{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi64_a4(i64 *%p) { | ||
| %v = load i64, i64* %p, align 4 | ||
| ret i64 %v | ||
| } | ||
|
|
||
| ; 8 is the default alignment for i32 so no attribute is needed. | ||
|
|
||
| ; CHECK-LABEL: ldi64_a8: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi64_a8(i64 *%p) { | ||
| %v = load i64, i64* %p, align 8 | ||
| ret i64 %v | ||
| } | ||
|
|
||
| ; The default alignment in LLVM is the same as the defualt alignment in wasm. | ||
|
|
||
| ; CHECK-LABEL: ldi64: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi64(i64 *%p) { | ||
| %v = load i64, i64* %p | ||
| ret i64 %v | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi64_a16: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=4{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi64_a16(i64 *%p) { | ||
| %v = load i64, i64* %p, align 16 | ||
| ret i64 %v | ||
| } | ||
|
|
||
| ; Extending loads. | ||
|
|
||
| ; CHECK-LABEL: ldi8_a1: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi8_a1(i8 *%p) { | ||
| %v = load i8, i8* %p, align 1 | ||
| %w = zext i8 %v to i64 | ||
| ret i64 %w | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi8_a2: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load8_u $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi8_a2(i8 *%p) { | ||
| %v = load i8, i8* %p, align 2 | ||
| %w = zext i8 %v to i64 | ||
| ret i64 %w | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi16_a1: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi16_a1(i16 *%p) { | ||
| %v = load i16, i16* %p, align 1 | ||
| %w = zext i16 %v to i64 | ||
| ret i64 %w | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi16_a2: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi16_a2(i16 *%p) { | ||
| %v = load i16, i16* %p, align 2 | ||
| %w = zext i16 %v to i64 | ||
| ret i64 %w | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi16_a4: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=2{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi16_a4(i16 *%p) { | ||
| %v = load i16, i16* %p, align 4 | ||
| %w = zext i16 %v to i64 | ||
| ret i64 %w | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi32_a1: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi32_a1(i32 *%p) { | ||
| %v = load i32, i32* %p, align 1 | ||
| %w = zext i32 %v to i64 | ||
| ret i64 %w | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi32_a2: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi32_a2(i32 *%p) { | ||
| %v = load i32, i32* %p, align 2 | ||
| %w = zext i32 %v to i64 | ||
| ret i64 %w | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi32_a4: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0){{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi32_a4(i32 *%p) { | ||
| %v = load i32, i32* %p, align 4 | ||
| %w = zext i32 %v to i64 | ||
| ret i64 %w | ||
| } | ||
|
|
||
| ; CHECK-LABEL: ldi32_a8: | ||
| ; CHECK-NEXT: .param i32{{$}} | ||
| ; CHECK-NEXT: .result i64{{$}} | ||
| ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=3{{$}} | ||
| ; CHECK-NEXT: return $pop[[NUM]]{{$}} | ||
| define i64 @ldi32_a8(i32 *%p) { | ||
| %v = load i32, i32* %p, align 8 | ||
| %w = zext i32 %v to i64 | ||
| ret i64 %w | ||
| } | ||
|
|
||
| ; Stores. | ||
|
|
||
| ; CHECK-LABEL: sti64_a1: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store $discard=, 0($0):p2align=0, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti64_a1(i64 *%p, i64 %v) { | ||
| store i64 %v, i64* %p, align 1 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti64_a2: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store $discard=, 0($0):p2align=1, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti64_a2(i64 *%p, i64 %v) { | ||
| store i64 %v, i64* %p, align 2 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti64_a4: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store $discard=, 0($0):p2align=2, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti64_a4(i64 *%p, i64 %v) { | ||
| store i64 %v, i64* %p, align 4 | ||
| ret void | ||
| } | ||
|
|
||
| ; 8 is the default alignment for i32 so no attribute is needed. | ||
|
|
||
| ; CHECK-LABEL: sti64_a8: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store $discard=, 0($0), $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti64_a8(i64 *%p, i64 %v) { | ||
| store i64 %v, i64* %p, align 8 | ||
| ret void | ||
| } | ||
|
|
||
| ; The default alignment in LLVM is the same as the defualt alignment in wasm. | ||
|
|
||
| ; CHECK-LABEL: sti64: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store $discard=, 0($0), $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti64(i64 *%p, i64 %v) { | ||
| store i64 %v, i64* %p | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti64_a16: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store $discard=, 0($0):p2align=4, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti64_a16(i64 *%p, i64 %v) { | ||
| store i64 %v, i64* %p, align 16 | ||
| ret void | ||
| } | ||
|
|
||
| ; Truncating stores. | ||
|
|
||
| ; CHECK-LABEL: sti8_a1: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store8 $discard=, 0($0), $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti8_a1(i8 *%p, i64 %w) { | ||
| %v = trunc i64 %w to i8 | ||
| store i8 %v, i8* %p, align 1 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti8_a2: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store8 $discard=, 0($0):p2align=1, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti8_a2(i8 *%p, i64 %w) { | ||
| %v = trunc i64 %w to i8 | ||
| store i8 %v, i8* %p, align 2 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti16_a1: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store16 $discard=, 0($0):p2align=0, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti16_a1(i16 *%p, i64 %w) { | ||
| %v = trunc i64 %w to i16 | ||
| store i16 %v, i16* %p, align 1 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti16_a2: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store16 $discard=, 0($0), $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti16_a2(i16 *%p, i64 %w) { | ||
| %v = trunc i64 %w to i16 | ||
| store i16 %v, i16* %p, align 2 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti16_a4: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store16 $discard=, 0($0):p2align=2, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti16_a4(i16 *%p, i64 %w) { | ||
| %v = trunc i64 %w to i16 | ||
| store i16 %v, i16* %p, align 4 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti32_a1: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store32 $discard=, 0($0):p2align=0, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti32_a1(i32 *%p, i64 %w) { | ||
| %v = trunc i64 %w to i32 | ||
| store i32 %v, i32* %p, align 1 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti32_a2: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store32 $discard=, 0($0):p2align=1, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti32_a2(i32 *%p, i64 %w) { | ||
| %v = trunc i64 %w to i32 | ||
| store i32 %v, i32* %p, align 2 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti32_a4: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store32 $discard=, 0($0), $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti32_a4(i32 *%p, i64 %w) { | ||
| %v = trunc i64 %w to i32 | ||
| store i32 %v, i32* %p, align 4 | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK-LABEL: sti32_a8: | ||
| ; CHECK-NEXT: .param i32, i64{{$}} | ||
| ; CHECK-NEXT: i64.store32 $discard=, 0($0):p2align=3, $1{{$}} | ||
| ; CHECK-NEXT: return{{$}} | ||
| define void @sti32_a8(i32 *%p, i64 %w) { | ||
| %v = trunc i64 %w to i32 | ||
| store i32 %v, i32* %p, align 8 | ||
| ret void | ||
| } |