blob: 6b06972808a0618e0625dfa4b6e9400aee516130 [file] [log] [blame] [edit]
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef wasm_ir_bits_h
#define wasm_ir_bits_h
#include "ir/literal-utils.h"
#include "support/bits.h"
#include "wasm-builder.h"
namespace wasm {
struct Bits {
// get a mask to keep only the low # of bits
static int32_t lowBitMask(int32_t bits) {
uint32_t ret = -1;
if (bits >= 32) {
return ret;
}
return ret >> (32 - bits);
}
// checks if the input is a mask of lower bits, i.e., all 1s up to some high
// bit, and all zeros from there. returns the number of masked bits, or 0 if
// this is not such a mask
static uint32_t getMaskedBits(uint32_t mask) {
if (mask == uint32_t(-1)) {
return 32; // all the bits
}
if (mask == 0) {
return 0; // trivially not a mask
}
// otherwise, see if adding one turns this into a 1-bit thing, 00011111 + 1
// => 00100000
if (PopCount(mask + 1) != 1) {
return 0;
}
// this is indeed a mask
return 32 - CountLeadingZeroes(mask);
}
// gets the number of effective shifts a shift operation does. In
// wasm, only 5 bits matter for 32-bit shifts, and 6 for 64.
static Index getEffectiveShifts(Index amount, Type type) {
if (type == Type::i32) {
return amount & 31;
} else if (type == Type::i64) {
return amount & 63;
}
WASM_UNREACHABLE("unexpected type");
}
static Index getEffectiveShifts(Expression* expr) {
auto* amount = expr->cast<Const>();
if (amount->type == Type::i32) {
return getEffectiveShifts(amount->value.geti32(), Type::i32);
} else if (amount->type == Type::i64) {
return getEffectiveShifts(amount->value.geti64(), Type::i64);
}
WASM_UNREACHABLE("unexpected type");
}
static Expression* makeSignExt(Expression* value, Index bytes, Module& wasm) {
if (value->type == Type::i32) {
if (bytes == 1 || bytes == 2) {
auto shifts = bytes == 1 ? 24 : 16;
Builder builder(wasm);
return builder.makeBinary(
ShrSInt32,
builder.makeBinary(
ShlInt32,
value,
LiteralUtils::makeFromInt32(shifts, Type::i32, wasm)),
LiteralUtils::makeFromInt32(shifts, Type::i32, wasm));
}
assert(bytes == 4);
return value; // nothing to do
} else {
assert(value->type == Type::i64);
if (bytes == 1 || bytes == 2 || bytes == 4) {
auto shifts = bytes == 1 ? 56 : (bytes == 2 ? 48 : 32);
Builder builder(wasm);
return builder.makeBinary(
ShrSInt64,
builder.makeBinary(
ShlInt64,
value,
LiteralUtils::makeFromInt32(shifts, Type::i64, wasm)),
LiteralUtils::makeFromInt32(shifts, Type::i64, wasm));
}
assert(bytes == 8);
return value; // nothing to do
}
}
};
} // namespace wasm
#endif // wasm_ir_bits_h