David Neto | 8508264 | 2018-03-24 06:55:20 -0700 | [diff] [blame] | 1 | // Copyright 2018 The Clspv Authors. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include "ConstantEmitter.h" |
| 16 | |
| 17 | #include <cassert> |
| 18 | |
| 19 | #include "llvm/ADT/APInt.h" |
| 20 | #include "llvm/ADT/APFloat.h" |
| 21 | #include "llvm/IR/Constants.h" |
| 22 | #include "llvm/IR/Value.h" |
| 23 | #include "llvm/Support/ErrorHandling.h" |
| 24 | |
| 25 | using namespace llvm; |
| 26 | |
| 27 | namespace clspv { |
| 28 | |
| 29 | void ConstantEmitter::Emit(Constant *c) { |
| 30 | AlignTo(Layout.getABITypeAlignment(c->getType())); |
| 31 | if (auto i = dyn_cast<ConstantInt>(c)) { |
| 32 | EmitInt(i); |
| 33 | } else if (auto f = dyn_cast<ConstantFP>(c)) { |
| 34 | EmitFP(f); |
| 35 | } else if (auto st = dyn_cast<ConstantStruct>(c)) { |
| 36 | EmitStruct(st); |
| 37 | } else if (auto ag = dyn_cast<ConstantArray>(c)) { |
| 38 | EmitAggregate(ag); |
| 39 | } else if (auto ag = dyn_cast<ConstantVector>(c)) { |
| 40 | EmitAggregate(ag); |
| 41 | } else if (auto cds = dyn_cast<ConstantDataSequential>(c)) { |
| 42 | EmitDataSequential(cds); |
| 43 | } else if (auto ag = dyn_cast<ConstantAggregate>(c)) { |
| 44 | EmitAggregate(ag); |
| 45 | } else if (auto ag = dyn_cast<ConstantAggregateZero>(c)) { |
| 46 | EmitAggregateZero(ag); |
| 47 | } else { |
| 48 | errs() << "Don't know how to emit " << *c << " with value id " |
| 49 | << int(c->getValueID()) << " compared to " << int(Value::ConstantVectorVal) |
| 50 | << "\n"; |
| 51 | llvm_unreachable("Unhandled constant"); |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | void ConstantEmitter::EmitZeroes(size_t n) { |
| 56 | for (size_t i = 0; i < n; ++i) { |
| 57 | Out << "00"; |
| 58 | ++Offset; |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | void ConstantEmitter::AlignTo(size_t alignment) { |
| 63 | size_t overflow = Offset % alignment; |
| 64 | if (overflow) { |
| 65 | const size_t padding = alignment - overflow; |
| 66 | EmitZeroes(padding); |
| 67 | } |
| 68 | assert(0 == (Offset % alignment)); |
| 69 | } |
| 70 | |
| 71 | void ConstantEmitter::EmitStruct(ConstantStruct *c) { |
| 72 | const StructLayout *sl = Layout.getStructLayout(c->getType()); |
| 73 | AlignTo(sl->getAlignment()); // Might be redundant. |
| 74 | const size_t BaseOffset = Offset; |
| 75 | for (unsigned i = 0; i < c->getNumOperands(); ++i) { |
| 76 | EmitZeroes(sl->getElementOffset(i) - (Offset - BaseOffset)); |
| 77 | Emit(c->getOperand(i)); |
| 78 | } |
| 79 | EmitZeroes(sl->getSizeInBytes() - (Offset - BaseOffset)); |
| 80 | } |
| 81 | |
| 82 | void ConstantEmitter::EmitDataSequential(ConstantDataSequential *c) { |
| 83 | for (unsigned i = 0; i < c->getNumElements(); ++i) { |
| 84 | // The elements will align themselves. |
| 85 | Constant *elem = c->getElementAsConstant(i); |
| 86 | Emit(elem); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | void ConstantEmitter::EmitAggregate(ConstantAggregate *c) { |
| 91 | for (unsigned i = 0; i < c->getNumOperands(); ++i) { |
| 92 | // The elements will align themselves. |
| 93 | Emit(c->getOperand(i)); |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | void ConstantEmitter::EmitAggregateZero(ConstantAggregateZero *c) { |
| 98 | if (StructType *sty = dyn_cast<StructType>(c->getType())) { |
| 99 | |
| 100 | const StructLayout *sl = Layout.getStructLayout(sty); |
| 101 | AlignTo(sl->getAlignment()); // Might be redundant. |
| 102 | const size_t BaseOffset = Offset; |
| 103 | for (unsigned i = 0; i < c->getNumElements(); ++i) { |
| 104 | EmitZeroes(sl->getElementOffset(i) - (Offset - BaseOffset)); |
| 105 | Emit(c->getElementValue(i)); |
| 106 | } |
| 107 | EmitZeroes(sl->getSizeInBytes() - (Offset - BaseOffset)); |
| 108 | |
| 109 | } else { |
| 110 | for (unsigned i = 0; i < c->getNumElements(); ++i) { |
| 111 | // The elements will align themselves. |
| 112 | Emit(c->getElementValue(i)); |
| 113 | } |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | void ConstantEmitter::EmitInt(ConstantInt *c) { |
| 118 | EmitRaw(c->getBitWidth(), c->getValue().getRawData()); |
| 119 | } |
| 120 | |
| 121 | void ConstantEmitter::EmitFP(ConstantFP *c) { |
| 122 | APInt asInt = c->getValueAPF().bitcastToAPInt(); |
| 123 | EmitRaw(asInt.getBitWidth(), asInt.getRawData()); |
| 124 | } |
| 125 | |
| 126 | void ConstantEmitter::EmitRaw(unsigned num_bits, const uint64_t *data) { |
| 127 | unsigned num_bytes = (num_bits + 7) / 8; |
| 128 | while (num_bytes) { |
| 129 | uint64_t word = *data++; |
| 130 | for (int i = 0; i < 8 && num_bytes; --num_bytes, ++i) { |
| 131 | EmitByte(word & 0xff); |
| 132 | word = (word >> 8); |
| 133 | } |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | void ConstantEmitter::EmitByte(size_t byte) { |
| 138 | static const char hex[] = "0123456789abcdef"; |
| 139 | Out << hex[(byte & 0xf0) >> 4] << hex[byte & 0xf]; |
| 140 | ++Offset; |
| 141 | } |
| 142 | |
| 143 | } // namespace clspv |